diff --git a/lib/classes/shutdown_manager.php b/lib/classes/shutdown_manager.php index 2a11ae2d090..b1c71ad7acc 100644 --- a/lib/classes/shutdown_manager.php +++ b/lib/classes/shutdown_manager.php @@ -80,10 +80,10 @@ class core_shutdown_manager { call_user_func_array($callback, $params); } } catch (Exception $e) { - error_log('Exception ignored in shutdown function '.var_export($callback, true).':'.$e->getMessage()); + error_log('Exception ignored in shutdown function '.get_callable_name($callback).': '.$e->getMessage()); } catch (Throwable $e) { // Engine errors in PHP7 throw exceptions of type Throwable (this "catch" will be ignored in PHP5). - error_log('Exception ignored in shutdown function '.var_export($callback, true).':'.$e->getMessage()); + error_log('Exception ignored in shutdown function '.get_callable_name($callback).': '.$e->getMessage()); } } diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 6d0fbfe2ed6..73e1c4d0a34 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -10110,3 +10110,22 @@ class lang_string { return $this->component; } } + +/** + * Get human readable name describing the given callable. + * + * This performs syntax check only to see if the given param looks like a valid function, method or closure. + * It does not check if the callable actually exists. + * + * @param callable|string|array $callable + * @return string|bool Human readable name of callable, or false if not a valid callable. + */ +function get_callable_name($callable) { + + if (!is_callable($callable, true, $name)) { + return false; + + } else { + return $name; + } +} diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index c429fb8f34d..163d795de10 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -4065,4 +4065,57 @@ class core_moodlelib_testcase extends advanced_testcase { ], ]; } + + /** + * Test that {@link get_callable_name()} describes the callable as expected. + * + * @dataProvider callable_names_provider + * @param callable $callable + * @param string $expectedname + */ + public function test_get_callable_name($callable, $expectedname) { + $this->assertSame($expectedname, get_callable_name($callable)); + } + + /** + * Provides a set of callables and their human readable names. + * + * @return array of (string)case => [(mixed)callable, (string|bool)expected description] + */ + public function callable_names_provider() { + return [ + 'integer' => [ + 386, + false, + ], + 'boolean' => [ + true, + false, + ], + 'static_method_as_literal' => [ + 'my_foobar_class::my_foobar_method', + 'my_foobar_class::my_foobar_method', + ], + 'static_method_of_literal_class' => [ + ['my_foobar_class', 'my_foobar_method'], + 'my_foobar_class::my_foobar_method', + ], + 'static_method_of_object' => [ + [$this, 'my_foobar_method'], + 'core_moodlelib_testcase::my_foobar_method', + ], + 'method_of_object' => [ + [new lang_string('parentlanguage', 'core_langconfig'), 'my_foobar_method'], + 'lang_string::my_foobar_method', + ], + 'function_as_literal' => [ + 'my_foobar_callback', + 'my_foobar_callback', + ], + 'function_as_closure' => [ + function($a) { return $a; }, + 'Closure::__invoke', + ], + ]; + } }