Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-32278

Lib: improve print_object to handle recursion, produce prettier output

XMLWordPrintable

    • MOODLE_23_STABLE, MOODLE_402_STABLE
    • MOODLE_403_STABLE
    • MDL-32278-master
    • Hide

      This test script involves making lots of temporary changes to code files. You also need to be able to run CLI commands and look at your web server logs.

      1. Edit mod/forum/view.php, and find the line (about line 170):

      echo $OUTPUT->header();
      

      Immediately after this line, add the following:

      print_object($cm);
      

      2. On your Moodle site, go to any forum.

      EXPECTED: You should see a display of the contents of the $cm variable, starting with the 'cm_info' class name shown in a blue badge.

      3. Look at and mouse over some of the object property names, e.g. 'modinfo'.

      EXPECTED: Popup text should show the property name followed by the access modifier (private, protected, or public) in brackets.
      EXPECTED: The on-screen display of these properties should be italic (private), normal (protected), or bold (public).

      4. Look at and mouse over some of the values, e.g. the strings shown on the right.

      EXPECTED: Popup text should show the type e.g. 'string'.
      EXPECTED: Strings should show in green with quotes. Null values should show as 'null' in italic, boolean values should show true/false in italic, numbers should show in blue.

      5. Look at some of the arrays.

      EXPECTED: The array heading should appear in a grey button with the number of items.
      EXPECTED: If you mouse over the array keys, it should show you the name and the type in brackets, like '0 (integer)'.

      6. Look for a circular reference, e.g. the 'modinfo' reference inside a cm_info inside the course_modinfo.

      EXPECTED: The circular references should be shown in red like [circular reference: course_modinfo].

      (You can now put back that temporary code change if you want.)

      7. Edit backup/backup.php and find the line (about line 244):

      $backup->destroy();
      

      Just before this line, add:

      print_object($backup, ['backup_ui', 'backup_controller', '/logger/']);
      

      8. On any course, go to the backup page (More > Course reuse > Backup) and look at the bottom.

      EXPECTED: Right at the bottom, you should see a display of the $backup object. Note that the backup_controller and all the *_logger classes are expanded (recursed into), but the backup_plan and backup_ui_stage_initial classes are not.

      9. Edit the last code line to add 'true':

      print_object($backup, ['backup_ui', 'backup_controller', '/logger/'], true);
      

      10. Reload the page.

      EXPECTED: The display at the bottom should now be a boring text-only display; it starts off something like this:

      [backup_ui]
        +controller = [backup_controller]
          +progress = [object: core\progress\display_if_slow]
          +logger = [error_log_logger]
            +level = 50
            +showdate = false
            +showlevel = false
            +next = [output_indented_logger]
              +level = 20
              +showdate = false
              +showlevel = false
              +next = [file_logger]
                +level = 50
                +showdate = true
                +showlevel = true
                +next = [database_logger]
                  +level = 50
                  +showdate = true
                  +showlevel = true
      

      (You can now put back that temporary code change if you want.)

      11. Edit admin/cli/cfg.php. Find the line (about line 106):

      if ($unrecognised) {
      

      Just before that line, add this:

      print_object($PAGE); exit;
      

      12. Run it as follows:

      php admin/cli/cfg.php
      

      EXPECTED: You should see something like this:

      [moodle_page]
        +_state = 0
        +_course = null
        +_cm = null
        +_module = null
        +_context = null
        +_categories = null
        +_bodyclasses = array (0)
        +_title = ''
        +_heading = ''
        +_pagetype = null
        +_pagelayout = 'base'
      

      (The + indicates protected, the * means private.)

      You can remove the temporary code now.

      13. Edit lib/ajax/service.php and find the following line (about line 45):

      $arguments = '';
      

      Just before this line, ad the following:

      print_object($PAGE);
      

      14. In your web browser, go to /lib/ajax/service.php.

      EXPECTED: You should get a JSON-format error message, containing text such as 'Invalid json in request: Syntax error'

      15. Find your web server's error.log and look at the end of it.

      EXPECTED: You should see lines containing the text-only format of the print_object output similar to the CLI output, such as the following:

      [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] [moodle_page]
      [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_state = 0
      [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_course = null
      [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_cm = null
      [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_module = null
      [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_context = null
      [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_categories = null
      [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357]   +_bodyclasses = array (0)
      ...
      

      (The final line should be from the default exception handler for the error message.)

      You can now remove the final temporary code change!

      Show
      This test script involves making lots of temporary changes to code files. You also need to be able to run CLI commands and look at your web server logs. 1. Edit mod/forum/view.php, and find the line (about line 170): echo $OUTPUT->header(); Immediately after this line, add the following: print_object($cm); 2. On your Moodle site, go to any forum. EXPECTED: You should see a display of the contents of the $cm variable, starting with the 'cm_info' class name shown in a blue badge. 3. Look at and mouse over some of the object property names, e.g. 'modinfo'. EXPECTED: Popup text should show the property name followed by the access modifier (private, protected, or public) in brackets. EXPECTED: The on-screen display of these properties should be italic (private), normal (protected), or bold (public). 4. Look at and mouse over some of the values, e.g. the strings shown on the right. EXPECTED: Popup text should show the type e.g. 'string'. EXPECTED: Strings should show in green with quotes. Null values should show as 'null' in italic, boolean values should show true/false in italic, numbers should show in blue. 5. Look at some of the arrays. EXPECTED: The array heading should appear in a grey button with the number of items. EXPECTED: If you mouse over the array keys, it should show you the name and the type in brackets, like '0 (integer)'. 6. Look for a circular reference, e.g. the 'modinfo' reference inside a cm_info inside the course_modinfo. EXPECTED: The circular references should be shown in red like [circular reference: course_modinfo] . (You can now put back that temporary code change if you want.) 7. Edit backup/backup.php and find the line (about line 244): $backup->destroy(); Just before this line, add: print_object($backup, ['backup_ui', 'backup_controller', '/logger/']); 8. On any course, go to the backup page (More > Course reuse > Backup) and look at the bottom. EXPECTED: Right at the bottom, you should see a display of the $backup object. Note that the backup_controller and all the *_logger classes are expanded (recursed into), but the backup_plan and backup_ui_stage_initial classes are not. 9. Edit the last code line to add 'true': print_object($backup, ['backup_ui', 'backup_controller', '/logger/'], true); 10. Reload the page. EXPECTED: The display at the bottom should now be a boring text-only display; it starts off something like this: [backup_ui] +controller = [backup_controller] +progress = [object: core\progress\display_if_slow] +logger = [error_log_logger] +level = 50 +showdate = false +showlevel = false +next = [output_indented_logger] +level = 20 +showdate = false +showlevel = false +next = [file_logger] +level = 50 +showdate = true +showlevel = true +next = [database_logger] +level = 50 +showdate = true +showlevel = true (You can now put back that temporary code change if you want.) 11. Edit admin/cli/cfg.php. Find the line (about line 106): if ($unrecognised) { Just before that line, add this: print_object($PAGE); exit; 12. Run it as follows: php admin/cli/cfg.php EXPECTED: You should see something like this: [moodle_page] +_state = 0 +_course = null +_cm = null +_module = null +_context = null +_categories = null +_bodyclasses = array (0) +_title = '' +_heading = '' +_pagetype = null +_pagelayout = 'base' (The + indicates protected, the * means private.) You can remove the temporary code now. 13. Edit lib/ajax/service.php and find the following line (about line 45): $arguments = ''; Just before this line, ad the following: print_object($PAGE); 14. In your web browser, go to /lib/ajax/service.php. EXPECTED: You should get a JSON-format error message, containing text such as 'Invalid json in request: Syntax error' 15. Find your web server's error.log and look at the end of it. EXPECTED: You should see lines containing the text-only format of the print_object output similar to the CLI output, such as the following: [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] [moodle_page] [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_state = 0 [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_course = null [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_cm = null [2023-08-09 15:48:18.229306 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_module = null [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_context = null [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_categories = null [2023-08-09 15:48:18.231810 GMT] [php:notice] [pid 7120:tid 1232] [client 127.0.0.1:52357] +_bodyclasses = array (0) ... (The final line should be from the default exception handler for the error message.) You can now remove the final temporary code change!

      When debugging code it is useful to call print_object. However print_object becomes useless in certain areas of code because objects contain recursion and can be deeply nested.

      This change:

      • Automatically prevents recursion problems (e.g. if you print modinfo, which contains a cm, which has a reference to modinfo).
      • Optionally allows speciific control of which objects to recurse into (you can list which classes to go into).
      • Has a pretty formatted display for web output, using Bootstrap classes with no CSS.
      • Has a concise text-only display for CLI output (to stderr) and AJAX output (to error log).

      Usage examples:

      // Same functionality as before, but no infinite recursion and prettier.
      print_object($anyobject); 
       
      // Only show top-level object and arrays, don't recurse into any object references.
      print_object($anyobject, []);
       
      // Recurse into object references, but only of listed classes.
      print_object($anyobject, ['my_class', 'stdClass', '/.*_listener$/']);
       
      // Display object in plain text without the fancy Bootstrap styling.
      print_object($anyobject, ['/./'], true);
      

      There are also some other parameters but these are intended for internal use (when it calls itself recursively).

      The pretty output uses different styles to indicate types, and should be fairly self-explanatory. When the name of a property gets cut off, or if you want more information like the type, you can mouse over to see it via a title attribute.

      I have attached a screenshot of the pretty output. Screenshot shows just part of the output of print_object($cm) for a forum; I'm mousing over the 'added' property name so that I can see it's private.

            quen Sam Marshall
            quen Sam Marshall
            Katie Ransom Katie Ransom
            Huong Nguyen Huong Nguyen
            Kim Jared Lucas Kim Jared Lucas
            Votes:
            2 Vote for this issue
            Watchers:
            7 Start watching this issue

              Created:
              Updated:
              Resolved:

                Estimated:
                Original Estimate - 0 minutes
                0m
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 2 hours, 32 minutes
                2h 32m

                  Error rendering 'clockify-timesheets-time-tracking-reports:timer-sidebar'. Please contact your Jira administrators.