mirror of
https://github.com/valitydev/thrift.git
synced 2024-11-07 02:45:22 +00:00
Thrift PHP generation Redux
Summary: Chopping the amount of code generated by Thrift for PHP services by two orders of magnitude (approx 25% of the previous size). This is done via putting more logic in a dynamic base class and taking it out of the generated code. Hopefully this wins back the CPU cycles paid just to load code from APC at the cost of a marginal increase in dynamic execution runtime. Reviewed By: sgrimm, dreiss Test Plan: Ran all the tests in trunk/test/php, also tested the API generate code and Falcon, etc. in my sandbox git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665328 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c0c88ee805
commit
5b743079da
@ -35,8 +35,9 @@ void t_php_generator::init_generator() {
|
||||
// Include other Thrift includes
|
||||
const vector<t_program*>& includes = program_->get_includes();
|
||||
for (size_t i = 0; i < includes.size(); ++i) {
|
||||
string package = includes[i]->get_name();
|
||||
f_types_ <<
|
||||
"include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + includes[i]->get_name() << "_types.php';" << endl;
|
||||
"include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << package << "/" << package << "_types.php';" << endl;
|
||||
}
|
||||
f_types_ << endl;
|
||||
|
||||
@ -283,6 +284,76 @@ void t_php_generator::generate_php_struct(t_struct* tstruct,
|
||||
generate_php_struct_definition(f_types_, tstruct, is_exception);
|
||||
}
|
||||
|
||||
void t_php_generator::generate_php_type_spec(ofstream& out,
|
||||
t_type* t) {
|
||||
t = get_true_type(t);
|
||||
indent(out) << "'type' => " << type_to_enum(t) << "," << endl;
|
||||
|
||||
if (t->is_base_type() || t->is_enum()) {
|
||||
// Noop, type is all we need
|
||||
} else if (t->is_struct() || t->is_xception()) {
|
||||
indent(out) << "'class' => '" << t->get_name() <<"'," << endl;
|
||||
} else if (t->is_map()) {
|
||||
t_type* ktype = get_true_type(((t_map*)t)->get_key_type());
|
||||
t_type* vtype = get_true_type(((t_map*)t)->get_val_type());
|
||||
indent(out) << "'ktype' => " << type_to_enum(ktype) << "," << endl;
|
||||
indent(out) << "'vtype' => " << type_to_enum(vtype) << "," << endl;
|
||||
indent(out) << "'key' => array(" << endl;
|
||||
indent_up();
|
||||
generate_php_type_spec(out, ktype);
|
||||
indent_down();
|
||||
indent(out) << ")," << endl;
|
||||
indent(out) << "'val' => array(" << endl;
|
||||
indent_up();
|
||||
generate_php_type_spec(out, vtype);
|
||||
indent(out) << ")," << endl;
|
||||
indent_down();
|
||||
} else if (t->is_list() || t->is_set()) {
|
||||
t_type* etype;
|
||||
if (t->is_list()) {
|
||||
etype = get_true_type(((t_list*)t)->get_elem_type());
|
||||
} else {
|
||||
etype = get_true_type(((t_set*)t)->get_elem_type());
|
||||
}
|
||||
indent(out) << "'etype' => " << type_to_enum(etype) <<"," << endl;
|
||||
indent(out) << "'elem' => array(" << endl;
|
||||
indent_up();
|
||||
generate_php_type_spec(out, etype);
|
||||
indent(out) << ")," << endl;
|
||||
indent_down();
|
||||
} else {
|
||||
throw "compiler error: no type for php struct spec field";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the struct specification structure, which fully qualifies enough
|
||||
* type information to generalize serialization routines.
|
||||
*/
|
||||
void t_php_generator::generate_php_struct_spec(ofstream& out,
|
||||
t_struct* tstruct) {
|
||||
indent(out) << "static $_TSPEC = array(" << endl;
|
||||
indent_up();
|
||||
|
||||
const vector<t_field*>& members = tstruct->get_members();
|
||||
vector<t_field*>::const_iterator m_iter;
|
||||
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
|
||||
t_type* t = get_true_type((*m_iter)->get_type());
|
||||
indent(out) << (*m_iter)->get_key() << " => array(" << endl;
|
||||
indent_up();
|
||||
out <<
|
||||
indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
|
||||
generate_php_type_spec(out, t);
|
||||
indent(out) << ")," << endl;
|
||||
indent_down();
|
||||
}
|
||||
|
||||
indent_down();
|
||||
indent(out) << " );" << endl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generates a struct definition for a thrift data type. This is nothing in PHP
|
||||
* where the objects are all just associative arrays (unless of course we
|
||||
@ -299,12 +370,16 @@ void t_php_generator::generate_php_struct_definition(ofstream& out,
|
||||
out <<
|
||||
"class " << php_namespace(tstruct->get_program()) << tstruct->get_name();
|
||||
if (is_exception) {
|
||||
out << " extends Exception";
|
||||
out << " extends TException";
|
||||
} else {
|
||||
out << " extends TBase";
|
||||
}
|
||||
out <<
|
||||
" {" << endl;
|
||||
indent_up();
|
||||
|
||||
generate_php_struct_spec(out, tstruct);
|
||||
|
||||
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
|
||||
string dval = "null";
|
||||
t_type* t = get_true_type((*m_iter)->get_type());
|
||||
@ -331,21 +406,12 @@ void t_php_generator::generate_php_struct_definition(ofstream& out,
|
||||
}
|
||||
|
||||
out <<
|
||||
indent() << "if (is_array($vals)) {" << endl;
|
||||
indent_up();
|
||||
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
|
||||
out <<
|
||||
indent() << "if (isset($vals['" << (*m_iter)->get_name() << "'])) {" << endl <<
|
||||
indent() << " $this->" << (*m_iter)->get_name() << " = $vals['" << (*m_iter)->get_name() << "'];" << endl <<
|
||||
indent() << "}" << endl;
|
||||
}
|
||||
indent_down();
|
||||
out <<
|
||||
indent() << "if (is_array($vals)) {" << endl <<
|
||||
indent() << " parent::construct(self::$_TSPEC, $vals);" << endl <<
|
||||
indent() << "}" << endl;
|
||||
indent_down();
|
||||
out <<
|
||||
indent() << "}" << endl <<
|
||||
endl;
|
||||
scope_down(out);
|
||||
|
||||
out << endl;
|
||||
}
|
||||
|
||||
out <<
|
||||
@ -372,9 +438,14 @@ void t_php_generator::generate_php_struct_reader(ofstream& out,
|
||||
vector<t_field*>::const_iterator f_iter;
|
||||
|
||||
indent(out) <<
|
||||
"public function read($input) " << endl;
|
||||
"public function read($input)" << endl;
|
||||
scope_up(out);
|
||||
|
||||
// TODO(mcslee): Testing this new jonx!
|
||||
indent(out) << "return $this->_read('" << tstruct->get_name() << "', self::$_TSPEC, $input);" << endl;
|
||||
scope_down(out);
|
||||
return;
|
||||
|
||||
out <<
|
||||
indent() << "$xfer = 0;" << endl <<
|
||||
indent() << "$fname = null;" << endl <<
|
||||
@ -496,6 +567,11 @@ void t_php_generator::generate_php_struct_writer(ofstream& out,
|
||||
}
|
||||
indent_up();
|
||||
|
||||
// TODO(mcslee): Testing this new j0nx
|
||||
indent(out) << "return $this->_write('" << tstruct->get_name() << "', self::$_TSPEC, $output);" << endl;
|
||||
scope_down(out);
|
||||
return;
|
||||
|
||||
indent(out) <<
|
||||
"$xfer = 0;" << endl;
|
||||
|
||||
@ -586,7 +662,9 @@ void t_php_generator::generate_service(t_service* tservice) {
|
||||
}
|
||||
generate_service_client(tservice);
|
||||
generate_service_helpers(tservice);
|
||||
generate_service_processor(tservice);
|
||||
if (phps_) {
|
||||
generate_service_processor(tservice);
|
||||
}
|
||||
|
||||
// Close service file
|
||||
f_service_ << "?>" << endl;
|
||||
@ -914,8 +992,13 @@ void t_php_generator::generate_service_rest(t_service* tservice) {
|
||||
t_type* atype = get_true_type((*a_iter)->get_type());
|
||||
string cast = type_to_cast(atype);
|
||||
string req = "$request['" + (*a_iter)->get_name() + "']";
|
||||
f_service_ <<
|
||||
indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl;
|
||||
if (atype->is_bool()) {
|
||||
f_service_ <<
|
||||
indent() << "$" << (*a_iter)->get_name() << " = " << cast << "(!empty(" << req << ") && (" << req << " !== 'false'));" << endl;
|
||||
} else {
|
||||
f_service_ <<
|
||||
indent() << "$" << (*a_iter)->get_name() << " = isset(" << req << ") ? " << cast << req << " : null;" << endl;
|
||||
}
|
||||
if (atype->is_string() &&
|
||||
((t_base_type*)atype)->is_string_list()) {
|
||||
f_service_ <<
|
||||
|
@ -21,13 +21,14 @@
|
||||
*/
|
||||
class t_php_generator : public t_oop_generator {
|
||||
public:
|
||||
t_php_generator(t_program* program, bool binary_inline=false, bool rest=false) :
|
||||
t_php_generator(t_program* program, bool binary_inline=false, bool rest=false, bool phps=false) :
|
||||
t_oop_generator(program),
|
||||
binary_inline_(binary_inline),
|
||||
rest_(rest) {
|
||||
rest_(rest),
|
||||
phps_(phps) {
|
||||
out_dir_base_ = (binary_inline_ ? "gen-phpi" : "gen-php");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init and close methods
|
||||
*/
|
||||
@ -58,6 +59,9 @@ class t_php_generator : public t_oop_generator {
|
||||
void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct);
|
||||
void generate_php_function_helpers(t_function* tfunction);
|
||||
|
||||
void generate_php_type_spec(std::ofstream &out, t_type* t);
|
||||
void generate_php_struct_spec(std::ofstream &out, t_struct* tstruct);
|
||||
|
||||
/**
|
||||
* Service-level generation functions
|
||||
*/
|
||||
@ -74,18 +78,18 @@ class t_php_generator : public t_oop_generator {
|
||||
*/
|
||||
|
||||
void generate_deserialize_field (std::ofstream &out,
|
||||
t_field* tfield,
|
||||
t_field* tfield,
|
||||
std::string prefix="",
|
||||
bool inclass=false);
|
||||
|
||||
|
||||
void generate_deserialize_struct (std::ofstream &out,
|
||||
t_struct* tstruct,
|
||||
std::string prefix="");
|
||||
|
||||
|
||||
void generate_deserialize_container (std::ofstream &out,
|
||||
t_type* ttype,
|
||||
std::string prefix="");
|
||||
|
||||
|
||||
void generate_deserialize_set_element (std::ofstream &out,
|
||||
t_set* tset,
|
||||
std::string prefix="");
|
||||
@ -159,6 +163,11 @@ class t_php_generator : public t_oop_generator {
|
||||
*/
|
||||
bool rest_;
|
||||
|
||||
/**
|
||||
* Generate stubs for a PHP server
|
||||
*/
|
||||
bool phps_;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -139,6 +139,7 @@ bool gen_py = false;
|
||||
bool gen_xsd = false;
|
||||
bool gen_php = false;
|
||||
bool gen_phpi = false;
|
||||
bool gen_phps = true;
|
||||
bool gen_rest = false;
|
||||
bool gen_perl = false;
|
||||
bool gen_erl = false;
|
||||
@ -559,6 +560,8 @@ void usage() {
|
||||
fprintf(stderr, " -javabean Generate Java bean-style output files\n");
|
||||
fprintf(stderr, " -php Generate PHP output files\n");
|
||||
fprintf(stderr, " -phpi Generate PHP inlined files\n");
|
||||
fprintf(stderr, " -phps Generate PHP server stubs (with -php)\n");
|
||||
fprintf(stderr, " -phpl Generate PHP-lite (with -php)\n");
|
||||
fprintf(stderr, " -py Generate Python output files\n");
|
||||
fprintf(stderr, " -rb Generate Ruby output files\n");
|
||||
fprintf(stderr, " -xsd Generate XSD output files\n");
|
||||
@ -775,7 +778,7 @@ void generate(t_program* program) {
|
||||
for (size_t i = 0; i < includes.size(); ++i) {
|
||||
// Propogate output path from parent to child programs
|
||||
includes[i]->set_out_path(program->get_out_path());
|
||||
|
||||
|
||||
generate(includes[i]);
|
||||
}
|
||||
}
|
||||
@ -810,7 +813,7 @@ void generate(t_program* program) {
|
||||
|
||||
if (gen_php) {
|
||||
pverbose("Generating PHP\n");
|
||||
t_php_generator* php = new t_php_generator(program, false, gen_rest);
|
||||
t_php_generator* php = new t_php_generator(program, false, gen_rest, gen_phps);
|
||||
php->generate_program();
|
||||
delete php;
|
||||
}
|
||||
@ -940,6 +943,16 @@ int main(int argc, char** argv) {
|
||||
gen_php = true;
|
||||
} else if (strcmp(arg, "-phpi") == 0) {
|
||||
gen_phpi = true;
|
||||
} else if (strcmp(arg, "-phps") == 0) {
|
||||
if (!gen_php) {
|
||||
gen_php = true;
|
||||
}
|
||||
gen_phps = true;
|
||||
} else if (strcmp(arg, "-phpl") == 0) {
|
||||
if (!gen_php) {
|
||||
gen_php = true;
|
||||
}
|
||||
gen_phps = false;
|
||||
} else if (strcmp(arg, "-rest") == 0) {
|
||||
gen_rest = true;
|
||||
} else if (strcmp(arg, "-py") == 0) {
|
||||
@ -972,7 +985,7 @@ int main(int argc, char** argv) {
|
||||
if (arg == NULL) {
|
||||
fprintf(stderr, "-o: missing output directory");
|
||||
usage();
|
||||
}
|
||||
}
|
||||
out_path = arg;
|
||||
struct stat sb;
|
||||
if (stat(out_path.c_str(), &sb) < 0) {
|
||||
|
@ -37,7 +37,7 @@ class t_base_type : public t_type {
|
||||
base_(base),
|
||||
string_list_(false),
|
||||
string_enum_(false) {}
|
||||
|
||||
|
||||
t_base get_base() const {
|
||||
return base_;
|
||||
}
|
||||
@ -49,7 +49,11 @@ class t_base_type : public t_type {
|
||||
bool is_string() const {
|
||||
return base_ == TYPE_STRING;
|
||||
}
|
||||
|
||||
|
||||
bool is_bool() const {
|
||||
return base_ == TYPE_BOOL;
|
||||
}
|
||||
|
||||
void set_string_list(bool val) {
|
||||
string_list_ = val;
|
||||
}
|
||||
@ -61,7 +65,7 @@ class t_base_type : public t_type {
|
||||
void set_binary(bool val) {
|
||||
binary_ = val;
|
||||
}
|
||||
|
||||
|
||||
bool is_binary() const {
|
||||
return (base_ == TYPE_STRING) && binary_;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ class t_type : public t_doc {
|
||||
virtual bool is_void() const { return false; }
|
||||
virtual bool is_base_type() const { return false; }
|
||||
virtual bool is_string() const { return false; }
|
||||
virtual bool is_bool() const { return false; }
|
||||
virtual bool is_typedef() const { return false; }
|
||||
virtual bool is_enum() const { return false; }
|
||||
virtual bool is_struct() const { return false; }
|
||||
|
@ -43,14 +43,711 @@ class TMessageType {
|
||||
const EXCEPTION = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE(mcslee): This currently contains a ton of duplicated code from TBase
|
||||
* because we need to save CPU cycles and this is not yet in an extension.
|
||||
* Ideally we'd multiply-inherit TException from both Exception and Base, but
|
||||
* that's not possible in PHP and there are no modules either, so for now we
|
||||
* apologetically take a trip to HackTown.
|
||||
*
|
||||
* Can be called with standard Exception constructor (message, code) or with
|
||||
* Thrift Base object constructor (spec, vals).
|
||||
*
|
||||
* @param mixed $p1 Message (string) or type-spec (array)
|
||||
* @param mixed $p2 Code (integer) or values (array)
|
||||
*/
|
||||
class TException extends Exception {
|
||||
function __construct($message=null, $code=0) {
|
||||
parent::__construct($message, $code);
|
||||
function __construct($p1=null, $p2=0) {
|
||||
if (is_array($p1) && is_array($p2)) {
|
||||
$spec = $p1;
|
||||
$vals = $p2;
|
||||
foreach ($spec as $fid => $fspec) {
|
||||
$var = $fspec['var'];
|
||||
if (isset($vals[$var])) {
|
||||
$this->$var = $vals[$var];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent::__construct($p1, $p2);
|
||||
}
|
||||
}
|
||||
|
||||
static $tmethod = array(TType::BOOL => 'Bool',
|
||||
TType::BYTE => 'Byte',
|
||||
TType::I16 => 'I16',
|
||||
TType::I32 => 'I32',
|
||||
TType::I64 => 'I64',
|
||||
TType::DOUBLE => 'Double',
|
||||
TType::STRING => 'String');
|
||||
|
||||
private function _readMap(&$var, $spec, $input) {
|
||||
$xfer = 0;
|
||||
$ktype = $spec['ktype'];
|
||||
$vtype = $spec['vtype'];
|
||||
$kread = $vread = null;
|
||||
if (isset(TBase::$tmethod[$ktype])) {
|
||||
$kread = 'read'.TBase::$tmethod[$ktype];
|
||||
} else {
|
||||
$kspec = $spec['key'];
|
||||
}
|
||||
if (isset(TBase::$tmethod[$vtype])) {
|
||||
$vread = 'read'.TBase::$tmethod[$vtype];
|
||||
} else {
|
||||
$vspec = $spec['val'];
|
||||
}
|
||||
$var = array();
|
||||
$_ktype = $_vtype = $size = 0;
|
||||
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
$key = $val = null;
|
||||
if ($kread !== null) {
|
||||
$xfer += $input->$kread($key);
|
||||
} else {
|
||||
switch ($ktype) {
|
||||
case TType::STRUCT:
|
||||
$class = $kspec['class'];
|
||||
$key = new $class();
|
||||
$xfer += $key->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($key, $kspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($key, $kspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($key, $kspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($vread !== null) {
|
||||
$xfer += $input->$vread($val);
|
||||
} else {
|
||||
switch ($vtype) {
|
||||
case TType::STRUCT:
|
||||
$class = $vspec['class'];
|
||||
$val = new $class();
|
||||
$xfer += $val->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($val, $vspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($val, $vspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($val, $vspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$var[$key] = $val;
|
||||
}
|
||||
$xfer += $input->readMapEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _readList(&$var, $spec, $input, $set=false) {
|
||||
$xfer = 0;
|
||||
$etype = $spec['etype'];
|
||||
$eread = $vread = null;
|
||||
if (isset(TBase::$tmethod[$etype])) {
|
||||
$eread = 'read'.TBase::$tmethod[$etype];
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
}
|
||||
$var = array();
|
||||
$_etype = $size = 0;
|
||||
if ($set) {
|
||||
$xfer += $input->readSetBegin($_etype, $size);
|
||||
} else {
|
||||
$xfer += $input->readListBegin($_etype, $size);
|
||||
}
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
$elem = null;
|
||||
if ($eread !== null) {
|
||||
$xfer += $input->$eread($elem);
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
switch ($etype) {
|
||||
case TType::STRUCT:
|
||||
$class = $espec['class'];
|
||||
$elem = new $class();
|
||||
$xfer += $elem->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($key, $espec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($key, $espec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($key, $espec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$var[$elem] = true;
|
||||
} else {
|
||||
$var []= $elem;
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $input->readSetEnd();
|
||||
} else {
|
||||
$xfer += $input->readListEnd();
|
||||
}
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
protected function _read($class, $spec, $input) {
|
||||
$xfer = 0;
|
||||
$fname = null;
|
||||
$ftype = 0;
|
||||
$fid = 0;
|
||||
$xfer += $input->readStructBegin($fname);
|
||||
$fast_binary = (bool)
|
||||
is_a($input, 'TBinaryProtocolAccelerated') &&
|
||||
function_exists('thrift_protocol_binary_deserialize');
|
||||
|
||||
while (true) {
|
||||
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
|
||||
if ($ftype == TType::STOP) {
|
||||
break;
|
||||
}
|
||||
if (isset($spec[$fid])) {
|
||||
$fspec = $spec[$fid];
|
||||
$var = $fspec['var'];
|
||||
if ($ftype == $fspec['type']) {
|
||||
$xfer = 0;
|
||||
if ($fast_binary) {
|
||||
$class = isset($fspec['class']) ? $fspec['class'] : null;
|
||||
$this->$var = thrift_protocol_binary_deserialize($ftype, $input, $class);
|
||||
} else {
|
||||
if (isset(TBase::$tmethod[$ftype])) {
|
||||
$func = 'read'.TBase::$tmethod[$ftype];
|
||||
$xter += $input->$func($this->$var);
|
||||
} else {
|
||||
switch ($ftype) {
|
||||
case TType::STRUCT:
|
||||
$class = $fspec['class'];
|
||||
$this->$var = new $class();
|
||||
$xfer += $this->$var->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($this->$var, $fspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($this->$var, $fspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($this->$var, $fspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
$xfer += $input->readFieldEnd();
|
||||
}
|
||||
$xfer += $input->readStructEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _writeMap($var, $spec, $output) {
|
||||
$xfer = 0;
|
||||
$ktype = $spec['ktype'];
|
||||
$vtype = $spec['vtype'];
|
||||
$kwrite = $vwrite = null;
|
||||
if (isset(TBase::$tmethod[$ktype])) {
|
||||
$kwrite = 'write'.TBase::$tmethod[$ktype];
|
||||
} else {
|
||||
$kspec = $spec['key'];
|
||||
}
|
||||
if (isset(TBase::$tmethod[$vtype])) {
|
||||
$vwrite = 'write'.TBase::$tmethod[$vtype];
|
||||
} else {
|
||||
$vspec = $spec['val'];
|
||||
}
|
||||
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
|
||||
foreach ($var as $key => $val) {
|
||||
if (isset($kwrite)) {
|
||||
$xfer += $output->$kwrite($key);
|
||||
} else {
|
||||
switch ($ktype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $key->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($key, $kspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($key, $kspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($key, $kspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($vwrite)) {
|
||||
$xfer += $output->$vwrite($val);
|
||||
} else {
|
||||
switch ($vtype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $val->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($val, $vspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($val, $vspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($val, $vspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeMapEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _writeList($var, $spec, $output, $set=false) {
|
||||
$xfer = 0;
|
||||
$etype = $spec['etype'];
|
||||
$ewrite = null;
|
||||
if (isset(TBase::$tmethod[$etype])) {
|
||||
$ewrite = 'write'.TBase::$tmethod[$etype];
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $output->writeSetBegin($etype, count($var));
|
||||
} else {
|
||||
$xfer += $output->writeListBegin($etype, count($var));
|
||||
}
|
||||
foreach ($var as $key => $val) {
|
||||
$elem = $set ? $key : $val;
|
||||
if (isset($ewrite)) {
|
||||
$xfer += $output->$ewrite($elem);
|
||||
} else {
|
||||
switch ($etype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $elem->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($elem, $espec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($elem, $espec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($elem, $espec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $output->writeSetEnd();
|
||||
} else {
|
||||
$xfer += $output->writeListEnd();
|
||||
}
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
protected function _write($class, $spec, $output) {
|
||||
$xfer = 0;
|
||||
$xfer += $output->writeStructBegin($class);
|
||||
foreach ($spec as $fid => $fspec) {
|
||||
$var = $fspec['var'];
|
||||
if ($this->$var !== null) {
|
||||
$ftype = $fspec['type'];
|
||||
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
|
||||
if (isset(TBase::$tmethod[$ftype])) {
|
||||
$func = 'write'.TBase::$tmethod[$ftype];
|
||||
$xter += $output->$func($this->$var);
|
||||
} else {
|
||||
switch ($ftype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $this->$var->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($this->$var, $fspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeFieldEnd();
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeFieldStop();
|
||||
$xfer += $output->writeStructEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class from which other Thrift structs extend. This is so that we can
|
||||
* cut back on the size of the generated code which is turning out to have a
|
||||
* nontrivial cost just to load thanks to the wondrously abysmal implementation
|
||||
* of PHP. Note that code is intentionally duplicated in here to avoid making
|
||||
* function calls for every field or member of a container..
|
||||
*/
|
||||
abstract class TBase {
|
||||
|
||||
static $tmethod = array(TType::BOOL => 'Bool',
|
||||
TType::BYTE => 'Byte',
|
||||
TType::I16 => 'I16',
|
||||
TType::I32 => 'I32',
|
||||
TType::I64 => 'I64',
|
||||
TType::DOUBLE => 'Double',
|
||||
TType::STRING => 'String');
|
||||
|
||||
abstract function read($input);
|
||||
|
||||
abstract function write($output);
|
||||
|
||||
public function __construct($spec=null, $vals=null) {
|
||||
if (is_array($spec) && is_array($vals)) {
|
||||
foreach ($spec as $fid => $fspec) {
|
||||
$var = $fspec['var'];
|
||||
if (isset($vals[$var])) {
|
||||
$this->$var = $vals[$var];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function _readMap(&$var, $spec, $input) {
|
||||
$xfer = 0;
|
||||
$ktype = $spec['ktype'];
|
||||
$vtype = $spec['vtype'];
|
||||
$kread = $vread = null;
|
||||
if (isset(TBase::$tmethod[$ktype])) {
|
||||
$kread = 'read'.TBase::$tmethod[$ktype];
|
||||
} else {
|
||||
$kspec = $spec['key'];
|
||||
}
|
||||
if (isset(TBase::$tmethod[$vtype])) {
|
||||
$vread = 'read'.TBase::$tmethod[$vtype];
|
||||
} else {
|
||||
$vspec = $spec['val'];
|
||||
}
|
||||
$var = array();
|
||||
$_ktype = $_vtype = $size = 0;
|
||||
$xfer += $input->readMapBegin($_ktype, $_vtype, $size);
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
$key = $val = null;
|
||||
if ($kread !== null) {
|
||||
$xfer += $input->$kread($key);
|
||||
} else {
|
||||
switch ($ktype) {
|
||||
case TType::STRUCT:
|
||||
$class = $kspec['class'];
|
||||
$key = new $class();
|
||||
$xfer += $key->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($key, $kspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($key, $kspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($key, $kspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($vread !== null) {
|
||||
$xfer += $input->$vread($val);
|
||||
} else {
|
||||
switch ($vtype) {
|
||||
case TType::STRUCT:
|
||||
$class = $vspec['class'];
|
||||
$val = new $class();
|
||||
$xfer += $val->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($val, $vspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($val, $vspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($val, $vspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$var[$key] = $val;
|
||||
}
|
||||
$xfer += $input->readMapEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _readList(&$var, $spec, $input, $set=false) {
|
||||
$xfer = 0;
|
||||
$etype = $spec['etype'];
|
||||
$eread = $vread = null;
|
||||
if (isset(TBase::$tmethod[$etype])) {
|
||||
$eread = 'read'.TBase::$tmethod[$etype];
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
}
|
||||
$var = array();
|
||||
$_etype = $size = 0;
|
||||
if ($set) {
|
||||
$xfer += $input->readSetBegin($_etype, $size);
|
||||
} else {
|
||||
$xfer += $input->readListBegin($_etype, $size);
|
||||
}
|
||||
for ($i = 0; $i < $size; ++$i) {
|
||||
$elem = null;
|
||||
if ($eread !== null) {
|
||||
$xfer += $input->$eread($elem);
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
switch ($etype) {
|
||||
case TType::STRUCT:
|
||||
$class = $espec['class'];
|
||||
$elem = new $class();
|
||||
$xfer += $elem->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($key, $espec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($key, $espec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($key, $espec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$var[$elem] = true;
|
||||
} else {
|
||||
$var []= $elem;
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $input->readSetEnd();
|
||||
} else {
|
||||
$xfer += $input->readListEnd();
|
||||
}
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
protected function _read($class, $spec, $input) {
|
||||
$xfer = 0;
|
||||
$fname = null;
|
||||
$ftype = 0;
|
||||
$fid = 0;
|
||||
$xfer += $input->readStructBegin($fname);
|
||||
$fast_binary = (bool)
|
||||
is_a($input, 'TBinaryProtocolAccelerated') &&
|
||||
function_exists('thrift_protocol_binary_deserialize');
|
||||
|
||||
while (true) {
|
||||
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
|
||||
if ($ftype == TType::STOP) {
|
||||
break;
|
||||
}
|
||||
if (isset($spec[$fid])) {
|
||||
$fspec = $spec[$fid];
|
||||
$var = $fspec['var'];
|
||||
if ($ftype == $fspec['type']) {
|
||||
$xfer = 0;
|
||||
if ($fast_binary) {
|
||||
$class = isset($fspec['class']) ? $fspec['class'] : null;
|
||||
$this->$var = thrift_protocol_binary_deserialize($ftype, $input, $class);
|
||||
} else {
|
||||
if (isset(TBase::$tmethod[$ftype])) {
|
||||
$func = 'read'.TBase::$tmethod[$ftype];
|
||||
$xter += $input->$func($this->$var);
|
||||
} else {
|
||||
switch ($ftype) {
|
||||
case TType::STRUCT:
|
||||
$class = $fspec['class'];
|
||||
$this->$var = new $class();
|
||||
$xfer += $this->$var->read($input);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_readMap($this->$var, $fspec, $input);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_readList($this->$var, $fspec, $input, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_readList($this->$var, $fspec, $input, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
$xfer += $input->readFieldEnd();
|
||||
}
|
||||
$xfer += $input->readStructEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _writeMap($var, $spec, $output) {
|
||||
$xfer = 0;
|
||||
$ktype = $spec['ktype'];
|
||||
$vtype = $spec['vtype'];
|
||||
$kwrite = $vwrite = null;
|
||||
if (isset(TBase::$tmethod[$ktype])) {
|
||||
$kwrite = 'write'.TBase::$tmethod[$ktype];
|
||||
} else {
|
||||
$kspec = $spec['key'];
|
||||
}
|
||||
if (isset(TBase::$tmethod[$vtype])) {
|
||||
$vwrite = 'write'.TBase::$tmethod[$vtype];
|
||||
} else {
|
||||
$vspec = $spec['val'];
|
||||
}
|
||||
$xfer += $output->writeMapBegin($ktype, $vtype, count($var));
|
||||
foreach ($var as $key => $val) {
|
||||
if (isset($kwrite)) {
|
||||
$xfer += $output->$kwrite($key);
|
||||
} else {
|
||||
switch ($ktype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $key->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($key, $kspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($key, $kspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($key, $kspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($vwrite)) {
|
||||
$xfer += $output->$vwrite($val);
|
||||
} else {
|
||||
switch ($vtype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $val->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($val, $vspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($val, $vspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($val, $vspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeMapEnd();
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
private function _writeList($var, $spec, $output, $set=false) {
|
||||
$xfer = 0;
|
||||
$etype = $spec['etype'];
|
||||
$ewrite = null;
|
||||
if (isset(TBase::$tmethod[$etype])) {
|
||||
$ewrite = 'write'.TBase::$tmethod[$etype];
|
||||
} else {
|
||||
$espec = $spec['elem'];
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $output->writeSetBegin($etype, count($var));
|
||||
} else {
|
||||
$xfer += $output->writeListBegin($etype, count($var));
|
||||
}
|
||||
foreach ($var as $key => $val) {
|
||||
$elem = $set ? $key : $val;
|
||||
if (isset($ewrite)) {
|
||||
$xfer += $output->$ewrite($elem);
|
||||
} else {
|
||||
switch ($etype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $elem->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($elem, $espec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($elem, $espec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($elem, $espec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($set) {
|
||||
$xfer += $output->writeSetEnd();
|
||||
} else {
|
||||
$xfer += $output->writeListEnd();
|
||||
}
|
||||
return $xfer;
|
||||
}
|
||||
|
||||
protected function _write($class, $spec, $output) {
|
||||
$xfer = 0;
|
||||
$xfer += $output->writeStructBegin($class);
|
||||
foreach ($spec as $fid => $fspec) {
|
||||
$var = $fspec['var'];
|
||||
if ($this->$var !== null) {
|
||||
$ftype = $fspec['type'];
|
||||
$xfer += $output->writeFieldBegin($var, $ftype, $fid);
|
||||
if (isset(TBase::$tmethod[$ftype])) {
|
||||
$func = 'write'.TBase::$tmethod[$ftype];
|
||||
$xter += $output->$func($this->$var);
|
||||
} else {
|
||||
switch ($ftype) {
|
||||
case TType::STRUCT:
|
||||
$xfer += $this->$var->write($output);
|
||||
break;
|
||||
case TType::MAP:
|
||||
$xfer += $this->_writeMap($this->$var, $fspec, $output);
|
||||
break;
|
||||
case TType::LST:
|
||||
$xfer += $this->_writeList($this->$var, $fspec, $output, false);
|
||||
break;
|
||||
case TType::SET:
|
||||
$xfer += $this->_writeList($this->$var, $fspec, $output, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeFieldEnd();
|
||||
}
|
||||
}
|
||||
$xfer += $output->writeFieldStop();
|
||||
$xfer += $output->writeStructEnd();
|
||||
return $xfer;
|
||||
}
|
||||
}
|
||||
|
||||
class TApplicationException extends TException {
|
||||
|
||||
static $_TSPEC =
|
||||
array(1 => array('var' => 'message',
|
||||
'type' => TType::STRING),
|
||||
2 => array('var' => 'code',
|
||||
'type' => TType::I32));
|
||||
|
||||
const UNKNOWN = 0;
|
||||
const UNKNOWN_METHOD = 1;
|
||||
const INVALID_MESSAGE_TYPE = 2;
|
||||
@ -62,55 +759,21 @@ class TApplicationException extends TException {
|
||||
parent::__construct($message, $code);
|
||||
}
|
||||
|
||||
public function read($input) {
|
||||
$xfer = 0;
|
||||
$fname = null;
|
||||
$ftype = 0;
|
||||
$fid = 0;
|
||||
$xfer += $input->readStructBegin($fname);
|
||||
while (true)
|
||||
{
|
||||
$xfer += $input->readFieldBegin($fname, $ftype, $fid);
|
||||
if ($ftype == TType::STOP) {
|
||||
break;
|
||||
}
|
||||
switch ($fid)
|
||||
{
|
||||
case 1:
|
||||
if ($ftype == TType::STRING) {
|
||||
$xfer += $input->readString($this->message);
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ($ftype == TType::I32) {
|
||||
$xfer += $input->readI32($this->code);
|
||||
} else {
|
||||
$xfer += $input->skip($ftype);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$xfer += $input->skip($ftype);
|
||||
break;
|
||||
}
|
||||
$xfer += $input->readFieldEnd();
|
||||
}
|
||||
$xfer += $input->readStructEnd();
|
||||
return $xfer;
|
||||
public function read($output) {
|
||||
return $this->_read('TApplicationException', self::$_TSPEC, $output);
|
||||
}
|
||||
|
||||
public function write($output) {
|
||||
$xfer = 0;
|
||||
$xfer += $output->writeStructBegin('TApplicationException');
|
||||
if ($this->getMessage()) {
|
||||
if ($message = $this->getMessage()) {
|
||||
$xfer += $output->writeFieldBegin('message', TType::STRING, 1);
|
||||
$xfer += $output->writeString($this->getMessage());
|
||||
$xfer += $output->writeString($message);
|
||||
$xfer += $output->writeFieldEnd();
|
||||
}
|
||||
if ($this->getCode()) {
|
||||
if ($code = $this->getCode()) {
|
||||
$xfer += $output->writeFieldBegin('type', TType::I32, 2);
|
||||
$xfer += $output->writeI32($this->getCode());
|
||||
$xfer += $output->writeI32($code);
|
||||
$xfer += $output->writeFieldEnd();
|
||||
}
|
||||
$xfer += $output->writeFieldStop();
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Makefile for Thrift test project.
|
||||
#
|
||||
#
|
||||
# Author:
|
||||
# Mark Slee <mcslee@facebook.com>
|
||||
|
||||
@ -16,7 +16,7 @@ normal: stubs
|
||||
inline: stubs-inline
|
||||
|
||||
stubs: ../ThriftTest.thrift
|
||||
$(THRIFT) --php ../ThriftTest.thrift
|
||||
$(THRIFT) --phpl ../ThriftTest.thrift
|
||||
|
||||
stubs-inline: ../ThriftTest.thrift
|
||||
$(THRIFT) --phpi ../ThriftTest.thrift
|
||||
|
@ -22,10 +22,18 @@ require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocketPool.php';
|
||||
/** Include the socket layer */
|
||||
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
|
||||
|
||||
echo '==============================='."\n";
|
||||
echo ' SAFE TO IGNORE THESE IN TEST'."\n";
|
||||
echo '==============================='."\n";
|
||||
|
||||
/** Include the generated code */
|
||||
require_once $GEN_DIR.'/ThriftTest.php';
|
||||
require_once $GEN_DIR.'/ThriftTest_types.php';
|
||||
|
||||
echo '==============================='."\n";
|
||||
echo ' END OF SAFE ERRORS SECTION'."\n";
|
||||
echo '==============================='."\n\n";
|
||||
|
||||
$host = 'localhost';
|
||||
$port = 9090;
|
||||
|
||||
@ -70,7 +78,7 @@ print_r(" = void\n");
|
||||
print_r("testString(\"Test\")");
|
||||
$s = $testClient->testString("Test");
|
||||
print_r(" = \"$s\"\n");
|
||||
|
||||
|
||||
/**
|
||||
* BYTE TEST
|
||||
*/
|
||||
@ -296,7 +304,7 @@ foreach ($whoa as $key => $val) {
|
||||
}
|
||||
}
|
||||
print_r("}, ");
|
||||
|
||||
|
||||
$xtructs = $v2->xtructs;
|
||||
print_r("{");
|
||||
if (is_array($xtructs)) {
|
||||
@ -306,7 +314,7 @@ foreach ($whoa as $key => $val) {
|
||||
}
|
||||
}
|
||||
print_r("}");
|
||||
|
||||
|
||||
print_r("}, ");
|
||||
}
|
||||
print_r("}, ");
|
||||
|
Loading…
Reference in New Issue
Block a user