From 7b9a0043d30c7607919882a1862ba455306697f7 Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Mon, 23 Oct 2023 16:59:14 +0900 Subject: [PATCH] Add Support::getCallStack returns full call stack for call (excluding self) --- 4dev/tests/Debug/CoreLibsDebugSupportTest.php | 27 +++++++++++- www/admin/class_test.datetime.php | 2 +- www/admin/class_test.debug.php | 4 ++ www/lib/CoreLibs/Debug/Support.php | 42 ++++++++++++++++--- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/4dev/tests/Debug/CoreLibsDebugSupportTest.php b/4dev/tests/Debug/CoreLibsDebugSupportTest.php index ab74df7d..74ed67ed 100644 --- a/4dev/tests/Debug/CoreLibsDebugSupportTest.php +++ b/4dev/tests/Debug/CoreLibsDebugSupportTest.php @@ -513,7 +513,7 @@ final class CoreLibsDebugSupportTest extends TestCase public function testGetCallerMethodList(array $expected): void { $compare = Support::getCallerMethodList(); - // 10: legact + // 10: legacy // 11: direct // 12: full call switch (count($compare)) { @@ -571,6 +571,31 @@ final class CoreLibsDebugSupportTest extends TestCase } } + /** + * Undocumented function + * + * @cover ::getCallStack + * @testdox getCallStack check if it returns data [$_dataName] + * + * @return void + */ + public function testGetCallStack(): void + { + $call_stack = Support::getCallStack(); + // print "Get CALL: " . print_r(Support::getCallStack(), true) . "\n"; + if ($call_stack < 8) { + $this->assertFalse(true, 'getCallStack too low: 8'); + } else { + $this->assertTrue(true, 'getCallSteck ok'); + } + // just test top entry + $first = array_shift($call_stack); + $this->assertStringEndsWith( + ':tests\CoreLibsDebugSupportTest->testGetCallStack', + $first, + ); + } + /** * test the lowest one (one above base) * diff --git a/www/admin/class_test.datetime.php b/www/admin/class_test.datetime.php index 55707bc0..7255c368 100644 --- a/www/admin/class_test.datetime.php +++ b/www/admin/class_test.datetime.php @@ -470,7 +470,7 @@ function intervalStringFormatDeprecated( // on first hit turn off (full off) if ($value) { $skip_last_zero = null; - } elseif (!$value && $skip_last_zero === false) { + } elseif ($skip_last_zero === false) { $zero_last_list[] = $part; } // build format diff --git a/www/admin/class_test.debug.php b/www/admin/class_test.debug.php index a19d8b9c..8141d383 100644 --- a/www/admin/class_test.debug.php +++ b/www/admin/class_test.debug.php @@ -170,6 +170,8 @@ class TestL { print "* GETCALLERCLASS(INSIDE CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "
"; print "* GETCALLERTOPCLASS(INSIDE CLASS): " . \CoreLibs\Debug\Support::getCallerTopLevelClass() . "
"; + print "* GETCALLSTACK(INSIDE CLASS):
"
+			. DebugSupport::prAr(\CoreLibs\Debug\Support::getCallStack()) . "

"; $this->log->debug('TESTL', 'Logging in class testL' . ($ts !== null ? ': ' . $ts : '')); $this->log->debug('TESTL', 'Some other message'); return true; @@ -193,6 +195,8 @@ class TestR extends TestL { print "** GETCALLERCLASS(INSIDE EXTND CLASS): " . \CoreLibs\Debug\Support::getCallerClass() . "
"; print "** GETCALLERTOPCLASS(INSIDE EXTND CLASS): " . \CoreLibs\Debug\Support::getCallerTopLevelClass() . "
"; + print "** GETCALLSTACK(INSIDE EXTND CLASS):
"
+			. DebugSupport::prAr(\CoreLibs\Debug\Support::getCallStack()) . "

"; $this->log->debug('TESTR', 'Logging in class testR (extends testL)'); $this->test('TESTR INSIDE'); $this->log->debug('TESTR', 'Array: ' diff --git a/www/lib/CoreLibs/Debug/Support.php b/www/lib/CoreLibs/Debug/Support.php index 456be11c..affec0f7 100644 --- a/www/lib/CoreLibs/Debug/Support.php +++ b/www/lib/CoreLibs/Debug/Support.php @@ -295,8 +295,7 @@ class Support * Will start with start_level to skip unwanted from stack * Defaults to skip level 0 wich is this methid * - * @param integer $start_level From what level on, as defaul starts with 1 - * to exclude self + * @param integer $start_level [=1] From what level on, starts with 1 to exclude self * @return array All method names in list where max is last called */ public static function getCallerMethodList(int $start_level = 1): array @@ -304,15 +303,46 @@ class Support $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $methods = []; foreach ($traces as $level => $data) { - if ($level >= $start_level) { - if (!empty($data['function'])) { - array_unshift($methods, $data['function']); - } + if ($level < $start_level) { + continue; + } + if (!empty($data['function'])) { + array_unshift($methods, $data['function']); } } return $methods; } + /** + * Get the full call stack from a certain starting level + * The return string is + * file:line:class->method + * + * Note that '::' is used for static calls + * + * @param int $start_level [=1] starts with 1 to exclude itself + * @return array string with file, line, class and method + */ + public static function getCallStack(int $start_level = 1): array + { + $call_stack = []; + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + foreach ($backtrace as $level => $call_trace) { + if ($level < $start_level) { + continue; + } + $call_stack[] = + ($call_trace['file'] ?? 'n/f') . ':' + . ($call_trace['line'] ?? '-') . ':' + . (!empty($call_trace['class']) ? + $call_trace['class'] . ($call_trace['type'] ?? '') : + '' + ) + . $call_trace['function']; + } + return $call_stack; + } + /** * Get the current class where this function is called * Is mostly used in debug log statements to get the class where the debug