Protocol Buffer For PHP


Protocol Buffer是什么:http://code.google.com/p/protobuf/ (Protocol Buffer 科普地址)

Protocol Buffer官方支持三种语言:C++、JAVA、Python,虽然PHP是WEB开发的主流语言,但是Google并未在给出官方支持

不过幸好有第三方开源程序:http://code.google.com/p/pb4php/

 

Protocol Buffer的优势:传输数据量小、解析效率高(相比XML,可节约60%~70%的数据通讯量(基于实际应用分析),解析效率并未进行实际数据的分析)

简单的说:Protocol Buffer就是通讯双方,定义好通信的规则;服务端对数据进行编码为二进制格式,客户端对收到的二进制数据进行解码,还原原始数据,并且与语言平台无关。

 

下面以当前移动互联网最为常见的通讯录云备份之间的通讯为实例进行分析(客户端请求保存在服务端的通讯录):

本例中不考虑用户身份的认证过程

1、编写消息格式文件
message PhonebookRequest
{
required string sid = 1;
required string user = 2;
}

message PhoneBase
{
required string user = 1;
required string phonenumber = 2;
optional int32 phonetype = 3;
}

message PhonebookResponse
{
required string sid = 1;
required int32 status = 2;
repeated PhoneBase phonebase = 3;
}

编写消息格式文件,Phonebook.proto,内容如上:包含三个消息,PhonebookRequest(请求消息),PhoneBase(响应中的通讯录的子消息),PhonebookResponse(响应消息),所有Porotocol Buffer的消息格式,与上述类似,一个message里,可以调用其他已经定义的message(不论调用的message是在该message外,还是message内),如上面的写法与如下写法没有差别。

message PhonebookRequest
{
required string sid = 1;
required string user = 2;
}

message PhonebookResponse
{
message PhoneBase
{
required string user = 1;
required string phonenumber = 2;
optional int32 phonetype = 3;
}
required string sid = 1;
required int32 status = 2;
repeated PhoneBase phonebase = 3;
}

PS:required为必选字段,optional为可选字段,repeated为可重复字段,string为字符串类型,int32为整形,以message名字为字段类型的,则表示该字段是一个message,更为完整的字段定义和使用,详见本文开头的Protocol Buffer的官方地址。

2、编写完proto文件后,则可通过开源程序中的parse程序进行 Protocol Buffer对象的生成了

生成后的文件如下pb_proto_Phonebook.php:
 

 

fields["1"] = "PBString";
    $this->values["1"] = "";
    $this->fields["2"] = "PBString";
    $this->values["2"] = "";
  }
  function sid()
  {
    return $this->_get_value("1");
  }
  function set_sid($value)
  {
    return $this->_set_value("1", $value);
  }
  function user()
  {
    return $this->_get_value("2");
  }
  function set_user($value)
  {
    return $this->_set_value("2", $value);
  }
}
class PhoneBase extends PBMessage
{
  var $wired_type = PBMessage::WIRED_LENGTH_DELIMITED;
  public function __construct($reader=null)
  {
    parent::__construct($reader);
    $this->fields["1"] = "PBString";
    $this->values["1"] = "";
    $this->fields["2"] = "PBString";
    $this->values["2"] = "";
    $this->fields["3"] = "PBInt";
    $this->values["3"] = "";
  }
  function user()
  {
    return $this->_get_value("1");
  }
  function set_user($value)
  {
    return $this->_set_value("1", $value);
  }
  function phonenumber()
  {
    return $this->_get_value("2");
  }
  function set_phonenumber($value)
  {
    return $this->_set_value("2", $value);
  }
  function phonetype()
  {
    return $this->_get_value("3");
  }
  function set_phonetype($value)
  {
    return $this->_set_value("3", $value);
  }
}
class PhonebookResponse extends PBMessage
{
  var $wired_type = PBMessage::WIRED_LENGTH_DELIMITED;
  public function __construct($reader=null)
  {
    parent::__construct($reader);
    $this->fields["1"] = "PBString";
    $this->values["1"] = "";
    $this->fields["2"] = "PBInt";
    $this->values["2"] = "";
    $this->fields["3"] = "PhoneBase";
    $this->values["3"] = array();
  }
  function sid()
  {
    return $this->_get_value("1");
  }
  function set_sid($value)
  {
    return $this->_set_value("1", $value);
  }
  function status()
  {
    return $this->_get_value("2");
  }
  function set_status($value)
  {
    return $this->_set_value("2", $value);
  }
  function phonebase($offset)
  {
    return $this->_get_arr_value("3", $offset);
  }
  function add_phonebase()
  {
    return $this->_add_arr_value("3");
  }
  function set_phonebase($index, $value)
  {
    $this->_set_arr_value("3", $index, $value);
  }
  function remove_last_phonebase()
  {
    $this->_remove_last_arr_value("3");
  }
  function phonebase_size()
  {
    return $this->_get_arr_size("3");
  }
}
?>

3、生成解析文件之后,该文件即可实现Protocol Buffer对象<=>二进制流之间的转换,但是项目中,会大量使用PHP数组,于是,可基于pb_proto_Phonebook.php中的代码实现Protocol Buffer对象<=>PHP数组之间的转换

ParseFromString($string);
		
		$result = array();
		$result['sid'] = $phonebook->sid();
		$result['status'] = $phonebook->status();
		
		$phonebaseSize = $phonebook->phonebase_size();
		for($i = 0; $i < $phonebaseSize; $i++)
		{
			$phonebase = $phonebook->phonebase($i);
			
			$result['phonebase'][] = array('user'=>$phonebase->user(), 'phonenumber'=>$phonebase->phonenumber(), 'phonetype'=>$phonebase->phonetype());
		}
		
		return $result;
	}
	
	static function serializeResponse($result)
	{
		$phonebook = new PhonebookResponse();
		$phonebook->set_sid($result['sid']);
		$phonebook->set_status($result['status']);
		
		if(!empty($result['phonebase'])){
			foreach($result['phonebase'] as $k=>$v)
			{
				$phonebase = $phonebook->add_phonebase();
				$phonebase->set_user($v['user']);
				$phonebase->set_phonenumber($v['phonenumber']);
				$phonebase->set_phonetype($v['phonetype']);
			}
		}
		
		return $phonebook->SerializeToString();
	}
}

$phonebook = array(
		'sid'		=>	'abc',
		'status'	=>	1,
		'phonebase'	=>	array(
				array('user'=>'单曲1', 'phonenumber'=>'13000000001', 'phonetype'=>'1'),
				array('user'=>'单曲2', 'phonenumber'=>'13000000002', 'phonetype'=>'1'),
				array('user'=>'单曲3', 'phonenumber'=>'13000000003', 'phonetype'=>'2'),
				
				)
		);
$string = Phonebook::serializeResponse($phonebook);//通讯中,传输的就是该二进制流

print_r(Phonebook::parseResponse($string));
?>

本例中的实例代码:phonebook.rar
如有问题,可留言。

,

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注