2

I'm getting a protobuf message (syntax 2) from another server in c++ and in another server in php, i'm receiving the same protobuf message(syntax 3). Now my purpose is to decode that message.

Below are the files:

The .proto file:

syntax="proto3";
message ModuleDescriptor {
string name = 1;
string identifier = 2;
string version = 3;
float frequency = 4;
}
message RuntimeStatistic {
double sliceConsumption = 1;
}

message ModuleStatistic {
ModuleDescriptor module = 1;
RuntimeStatistic runtimeStatistic = 2;
}
message ModuleStatistics {
repeated ModuleStatistic moduleStatistics = 1; //this is the message that i receive
}

This proto file generates 4 classes. Here is the class ModuleStatistics:

<?php
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: ModuleStatistics.proto

use Google\Protobuf\Internal\GPBType;
use Google\Protobuf\Internal\RepeatedField;
use Google\Protobuf\Internal\GPBUtil;

/**
* Protobuf type <code>ModuleStatistics</code>
*/
class ModuleStatistics extends \Google\Protobuf\Internal\Message
{
/**
 * <code>repeated .ModuleStatistic moduleStatistics = 1;</code>
 */
private $moduleStatistics;

public function __construct() {
    \GPBMetadata\ModuleStatistics::initOnce();
    parent::__construct();
}

/**
 * <code>repeated .ModuleStatistic moduleStatistics = 1;</code>
 */
public function getModuleStatistics()
{
    return $this->moduleStatistics;
}

/**
 * <code>repeated .ModuleStatistic moduleStatistics = 1;</code>
 */
public function setModuleStatistics(&$var)
{
    $arr = GPBUtil::checkRepeatedField($var, \Google\Protobuf\Internal\GPBType::MESSAGE, \ModuleStatistic::class);
    $this->moduleStatistics = $arr;
  }

}

index.php file:

include_once './vendor/autoload.php';
require_once("generated_proto/GPBMetadata/ModuleStatistics.php");
require_once("generated_proto/ModuleDescriptor.php");
require_once("generated_proto/RuntimeStatistic.php");
require_once("generated_proto/ModuleStatistic.php");
require_once("generated_proto/ModuleStatistics.php");
...
$protoClass = new ModuleStatistics();      //MoudleStatitistics is a generated class from protobuff
$protoClass -> mergeFromString($receivedString);       //decode the string       received from the c++ server
echo $protoClass ->getModuleStatistics();       // getModuleStatisics() is a function in the generated class ModulseStatistics.
...

This is all the code i have for protocol buffers.

Now when i try to get inside the getModuleStatistics() function, it throws me this error: PHP Catchable fatal error: Object of class ModuleStatistics could not be converted to string in /app/index.php on line 41

mergeFromString() doesnt give me any error but it doesnt retrun anything neither.

I am only receiving 1 of the 4 messages of the proto file. But as you can see its a nested message. Do i need to receive all 4 messages? And then maybe set them to each other?

Fisnik Hajredini
  • 111
  • 5
  • 13

1 Answers1

1

Update

Looking at your .proto file it appears that the actual data that you want to get at is still nested a little deeper...

The object hierarchy for the PHP classes generated from your proto file looks a little like this:

ModuleStatistics
    |
    +---- ModuleStatistic
    |         |
    |         +---- ModuleDescriptor
    |         |
    |         +---- RuntimeStatistic
    |
    +---- ModuleStatistic
              |
              +---- ModuleDescriptor
              |
              +---- RuntimeStatistic

That is to say ModuleStatistics is an iterable object possibly containing multiple individual ModuleStatistic objects - zero or more.

Each ModuleStatistic object contains two further objects - ModuleDescriptor and RuntimeStatistic, which are the value objects containing the actual data that you presumably want to print out or otherwise use in your program.

These objects contain getters for their data and I recommend you read the generated PHP classes to get familiar with the specific interfaces that are being generated for them.

In summary, you should be able to do something like this to echo out individual values:

// First, let's grab the return value from `getModuleStatistics()`
// which is a `ModuleStatistics` object

$moduleStatistics = $protoClass->getModuleStatistics();

// `ModuleStatistics` is an object that implements PHP's 
// `Iterator` interface, meaning you can iterate over it 
// with `foreach`. It will return zero or more nested 
// `ModuleStatistic` objects

foreach ($moduleStatistics as $moduleStatistic) {

    // Each `ModuleStatistic` itself contains two more nested
    // objects: `RuntimeStatistic` and `ModuleDescriptor`

    $runtimeStatistic = $moduleStatistic->getRuntimeStatistic();
    $moduleDescriptor = $moduleStatistic->getModule();

    // these nested objects contain the actual 
    // scalar values that you can echo

    echo $runtimeStatistic->getSliceConsumption(); // returns a double
    echo $moduleDescriptor->getName(); // returns a string
    echo $moduleDescriptor->getIdentifier(); // returns a string
    echo $moduleDescriptor->getVersion(); // returns a string
    echo $moduleDescriptor->getFrequency(); // returns a double
}

I obviously haven't tested this code because I don't have your data so YMMV. If in doubt about the return values of methods, read the generated code or use var_dump() or print_r() to inspect variable contents.

Hope this helps.


With regard to the following error:

PHP Catchable fatal error: Object of class ModuleStatistics could not be converted to string in /app/index.php on line 41

The line echo $protoClass ->getModuleStatistics(); is returning an instance of the class ModuleStatistics which you are then trying to echo.

It cannot do that because ModuleStatistics does not have a __toString() method. So either don't try to echo the object, or add a __toString() method; e.g:

<?php

class ModuleStatistics
{
    // etc.

    public function __toString()
    {
        // `return` the desired string representation of your object here
    }
}

Reference:

Darragh Enright
  • 13,676
  • 7
  • 41
  • 48
  • I tried echoing it as i has no other idea on how to do it.I added the generated file in the question. It says on the file not to edit it tho, should i still add that function. And if i add it, what string would i be returning? – Fisnik Hajredini Aug 06 '17 at 12:09
  • @FisnikHajredini - This is an automatically generated class? Then no - don't create a `__toString()` method, because it will be overwritten. – Darragh Enright Aug 06 '17 at 14:57
  • With regard to `Message::mergeFromString()` - you're correct, it doesn't return anything - that's by design: https://github.com/google/protobuf/blob/master/php/src/Google/Protobuf/Internal/Message.php#L577 – Darragh Enright Aug 06 '17 at 14:58
  • So the question is - we know you cannot `echo` a class without providing a `__toString()` implementation, and we know that we cannot do that in this case because `ModuleStatistics` is an auto-generated class. So the core question is - what do you want to do with this object? – Darragh Enright Aug 06 '17 at 15:02
  • That message contains a string with information. I will be receiving a message every second and i need to display it. Which means i have to decode it to a string. Is there any way that you can do this? why would u need that object if u cant decode it to human readable string. – Fisnik Hajredini Aug 06 '17 at 19:11
  • my ModuleStatistics.php was the wrong one, i added `ModuleStatistic.php`(without the "s") by accident. Fixed it now. `getModuleStatistics` doesnt return a class of `ModuleStatistic`, it returns the class `ModuleStatistics` – Fisnik Hajredini Aug 08 '17 at 12:30
  • Great. If you feel that my answer or comments helped you feel free to upvote or marked the question as answered. – Darragh Enright Aug 08 '17 at 23:56