summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Slee <mcslee@apache.org>2007-11-13 04:00:29 +0000
committerMark Slee <mcslee@apache.org>2007-11-13 04:00:29 +0000
commit5b743079da3b0f817545d7e0574222a5c16fc2a9 (patch)
tree16e0768d3a13702182643c7e00d1c4909132de81
parentc0c88ee8056427f66451e527f791b31f7485b4ca (diff)
downloadthrift-5b743079da3b0f817545d7e0574222a5c16fc2a9.tar.gz
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
-rw-r--r--compiler/cpp/src/generate/t_php_generator.cc123
-rw-r--r--compiler/cpp/src/generate/t_php_generator.h23
-rw-r--r--compiler/cpp/src/main.cc19
-rw-r--r--compiler/cpp/src/parse/t_base_type.h10
-rw-r--r--compiler/cpp/src/parse/t_type.h1
-rw-r--r--lib/php/src/Thrift.php729
-rw-r--r--test/php/Makefile4
-rw-r--r--test/php/TestClient.php14
8 files changed, 852 insertions, 71 deletions
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 2fb4e1855..848e9177d 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -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_ <<
diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h
index 1f2e2584a..574274749 100644
--- a/compiler/cpp/src/generate/t_php_generator.h
+++ b/compiler/cpp/src/generate/t_php_generator.h
@@ -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
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 468a7b069..c633facb6 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -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) {
diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h
index 929bf74f0..a44038006 100644
--- a/compiler/cpp/src/parse/t_base_type.h
+++ b/compiler/cpp/src/parse/t_base_type.h
@@ -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_;
}
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
index 3144356a0..b9da4fd5f 100644
--- a/compiler/cpp/src/parse/t_type.h
+++ b/compiler/cpp/src/parse/t_type.h
@@ -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; }
diff --git a/lib/php/src/Thrift.php b/lib/php/src/Thrift.php
index 21a175c01..9c7b4e62e 100644
--- a/lib/php/src/Thrift.php
+++ b/lib/php/src/Thrift.php
@@ -43,56 +43,560 @@ 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);
+ }
}
-}
-class TApplicationException extends TException {
-
- const UNKNOWN = 0;
- const UNKNOWN_METHOD = 1;
- const INVALID_MESSAGE_TYPE = 2;
- const WRONG_METHOD_NAME = 3;
- const BAD_SEQUENCE_ID = 4;
- const MISSING_RESULT = 5;
+ static $tmethod = array(TType::BOOL => 'Bool',
+ TType::BYTE => 'Byte',
+ TType::I16 => 'I16',
+ TType::I32 => 'I32',
+ TType::I64 => 'I64',
+ TType::DOUBLE => 'Double',
+ TType::STRING => 'String');
- function __construct($message=null, $code=0) {
- parent::__construct($message, $code);
+ 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;
}
- public function read($input) {
+ 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);
- while (true)
- {
+ $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;
}
- switch ($fid)
- {
- case 1:
- if ($ftype == TType::STRING) {
- $xfer += $input->readString($this->message);
+ 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 {
- $xfer += $input->skip($ftype);
+ 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 2:
- if ($ftype == TType::I32) {
- $xfer += $input->readI32($this->code);
- } else {
- $xfer += $input->skip($ftype);
+ 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;
- default:
- $xfer += $input->skip($ftype);
+ 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();
}
@@ -100,17 +604,176 @@ class TApplicationException extends TException {
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;
+ const WRONG_METHOD_NAME = 3;
+ const BAD_SEQUENCE_ID = 4;
+ const MISSING_RESULT = 5;
+
+ function __construct($message=null, $code=0) {
+ parent::__construct($message, $code);
+ }
+
+ 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();
diff --git a/test/php/Makefile b/test/php/Makefile
index 57c621c5b..6cc52333a 100644
--- a/test/php/Makefile
+++ b/test/php/Makefile
@@ -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
diff --git a/test/php/TestClient.php b/test/php/TestClient.php
index 07068e403..a508512a2 100644
--- a/test/php/TestClient.php
+++ b/test/php/TestClient.php
@@ -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("}, ");