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:
Mark Slee 2007-11-13 04:00:29 +00:00
parent c0c88ee805
commit 5b743079da
8 changed files with 862 additions and 81 deletions

View File

@ -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_ <<

View File

@ -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

View File

@ -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) {

View File

@ -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_;
}

View File

@ -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; }

View File

@ -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();

View File

@ -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

View File

@ -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("}, ");