Skip to content

PHP: use __debugInfo in Message to fix endless var_dump #12714

@bshaffer

Description

@bshaffer

Debugging a Protobuf Message Object

Calling var_dump or print_r on a protobuf message with the Protobuf C extension enabled results very limited, not very useful output:

// Calling var_dump on a Protobuf message (extension enabled):
php > var_dump(new Google\Protobuf\Timestamp());
object(Google\Protobuf\Timestamp)#1 (0) {
}

// Calling print_r on a Protobuf message (extension enabled):
php > var_dump(new Google\Protobuf\Timestamp());
Google\Protobuf\Timestamp Object

When using the Protobuf native library, calls to var_dump and print_r are hard to read and filled with noise:

// Calling var_dump on a Protobuf message (extension disabled):
php > var_dump(new Google\Protobuf\Timestamp());
object(Google\Protobuf\Timestamp)#2 (4) {
  ["desc":"Google\Protobuf\Internal\Message":private]=>
  object(Google\Protobuf\Internal\Descriptor)#424 (13) {
    ["full_name":"Google\Protobuf\Internal\Descriptor":private]=>
    string(25) "google.protobuf.Timestamp"
    ["field":"Google\Protobuf\Internal\Descriptor":private]=>
    array(2) {
      [1]=>
      object(Google\Protobuf\Internal\FieldDescriptor)#428 (14) {
        ["name":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        string(7) "seconds"
        ["json_name":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        string(7) "seconds"
        ["setter":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        string(10) "setSeconds"
        ["getter":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        string(10) "getSeconds"
        ["number":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        int(1)
        ["label":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        int(1)
        ["type":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        int(3)
        ["message_type":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        NULL
        ["enum_type":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        NULL
        ["packed":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        bool(false)
        ["oneof_index":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        int(-1)
        ["proto3_optional":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        bool(false)
        ["containing_oneof":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        NULL
        ["public_desc":"Google\Protobuf\Internal\FieldDescriptor":private]=>
        object(Google\Protobuf\FieldDescriptor)#429 (1) {
          ["internal_desc":"Google\Protobuf\FieldDescriptor":private]=>
          *RECURSION*
        }
      }
// ...

// Calling print_r on a Protobuf message (extension disabled):
php > var_dump(new Google\Protobuf\Timestamp());
Google\Protobuf\Timestamp Object
(
    [desc:Google\Protobuf\Internal\Message:private] => Google\Protobuf\Internal\Descriptor Object
        (
            [full_name:Google\Protobuf\Internal\Descriptor:private] => google.protobuf.Timestamp
            [field:Google\Protobuf\Internal\Descriptor:private] => Array
                (
                    [1] => Google\Protobuf\Internal\FieldDescriptor Object
                        (
                            [name:Google\Protobuf\Internal\FieldDescriptor:private] => seconds
                            [json_name:Google\Protobuf\Internal\FieldDescriptor:private] => seconds
                            [setter:Google\Protobuf\Internal\FieldDescriptor:private] => setSeconds
                            [getter:Google\Protobuf\Internal\FieldDescriptor:private] => getSeconds
                            [number:Google\Protobuf\Internal\FieldDescriptor:private] => 1
                            [label:Google\Protobuf\Internal\FieldDescriptor:private] => 1
                            [type:Google\Protobuf\Internal\FieldDescriptor:private] => 3
                            [message_type:Google\Protobuf\Internal\FieldDescriptor:private] => 
                            [enum_type:Google\Protobuf\Internal\FieldDescriptor:private] => 
                            [packed:Google\Protobuf\Internal\FieldDescriptor:private] => 
                            [oneof_index:Google\Protobuf\Internal\FieldDescriptor:private] => -1
                            [proto3_optional:Google\Protobuf\Internal\FieldDescriptor:private] => 
                            [containing_oneof:Google\Protobuf\Internal\FieldDescriptor:private] => 
                            [public_desc:Google\Protobuf\Internal\FieldDescriptor:private] => Google\Protobuf\FieldDescriptor Object
                                (
                                    [internal_desc:Google\Protobuf\FieldDescriptor:private] => Google\Protobuf\Internal\FieldDescriptor Object
 *RECURSION*
//...

This problem is even worse when debugging instances of RepeatedField, as the result is never-ending.

The fix for this would involve adding support for __debugInfo in the Message class:

    public function __debugInfo()
    {
        return (array) json_decode($this->serializeToJsonString(), true);
    }

For better handling , we can add support for checking specific types (e.g. Google\Protobuf\Timestamp, which returns a string for serializeToJsonString) and adding __debugInfo() for specific classes such as RepeatedField.

Metadata

Metadata

Assignees

Labels

inactiveDenotes the issue/PR has not seen activity in the last 90 days.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions