Thrift compiler support for inline PHP client code

Summary: Option to generate inline PHP code, as well as support for the async modifier keyword and the abstraction of function calls into a send and recv component




git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664740 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/Makefile b/compiler/Makefile
index 26a8b31..6b12853 100644
--- a/compiler/Makefile
+++ b/compiler/Makefile
@@ -35,9 +35,9 @@
 # Source files
 SRC_FILES = main.cc \
             generate/t_generator.cc \
+            generate/t_php_generator.cc \
             generate/t_cpp_generator.cc \
-            generate/t_java_generator.cc \
-            generate/t_php_generator.cc
+            generate/t_java_generator.cc
 
 # Autogenerated files
 GEN_FILES = thrift.tab.hh \
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
index b4ad135..6014e5f 100644
--- a/compiler/src/generate/t_cpp_generator.cc
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -220,7 +220,18 @@
   vector<t_function*> functions = tservice->get_functions();
   vector<t_function*>::const_iterator f_iter; 
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_function send_function(g_program->get_void_type(),
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
     indent(f_header_) << function_signature(*f_iter) << ";" << endl;
+    indent(f_header_) << function_signature(&send_function) << ";" << endl;
+    if (!(*f_iter)->is_async()) {
+      t_struct noargs;
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      indent(f_header_) << function_signature(&recv_function) << ";" << endl;
+    }
   }
   indent_down();
   
@@ -245,8 +256,47 @@
     string funname = (*f_iter)->get_name();
 
     // Open function
-    f_service_ <<
-      function_signature(*f_iter, scope) << "" << endl;
+    indent(f_service_) <<
+      function_signature(*f_iter, scope) << endl;
+    scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_async()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+
+    t_function send_function(g_program->get_void_type(),
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    // Open function
+    indent(f_service_) <<
+      function_signature(&send_function, scope) << endl;
     scope_up(f_service_);
 
     // Serialize the request
@@ -273,33 +323,48 @@
     // Flush the request
     indent(f_service_) <<
       "_otrans->flush();" << endl;
-
-    // Read the response
-    t_struct result_struct((*f_iter)->get_name() + "_result");
-    t_field result_field((*f_iter)->get_returntype(), "_result");
-
-    // Add a field to the return struct if non void
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      indent(f_service_) <<
-        type_name((*f_iter)->get_returntype()) << " _result;" << endl;
-      result_struct.append(&result_field);
-    }
-
-    // Deserialize response struct
-    generate_deserialize_struct(&result_struct);
-
-    // Careful, only return _result if not a void function
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      indent(f_service_) <<
-        "return _result;" << endl;
-    } else {
-      indent(f_service_) <<
-        "return;" << endl;
-    }
-
-    // Close function
+    
     scope_down(f_service_);
-    indent(f_service_) << endl;
+    f_service_ << endl;
+
+    if (!(*f_iter)->is_async()) {
+      t_struct noargs;
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      indent(f_service_) <<
+        function_signature(&recv_function, scope) << endl;
+      scope_up(f_service_);
+
+      // Read the response
+      t_struct result_struct((*f_iter)->get_name() + "_result");
+      t_field result_field((*f_iter)->get_returntype(), "_result");
+      
+      // Add a field to the return struct if non void
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          type_name((*f_iter)->get_returntype()) << " _result;" << endl;
+        result_struct.append(&result_field);
+      }
+      
+      // Deserialize response struct
+      generate_deserialize_struct(&result_struct);
+      
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return _result;" << endl;
+      } else {
+        indent(f_service_) <<
+          "return;" << endl;
+      }
+      
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
+
   }
 }
 
diff --git a/compiler/src/generate/t_java_generator.cc b/compiler/src/generate/t_java_generator.cc
index e4236fc..13b5022 100644
--- a/compiler/src/generate/t_java_generator.cc
+++ b/compiler/src/generate/t_java_generator.cc
@@ -33,7 +33,6 @@
     "import java.util.HashMap;\n" +
     "import java.util.HashSet;\n" +
     "import com.facebook.thrift.*;\n" +
-    "import com.facebook.thrift.types.*;\n" +
     "import com.facebook.thrift.protocol.TString;\n\n";
 }
 
@@ -73,8 +72,7 @@
 
   f_enum <<
     autogen_comment() <<
-    java_package() <<
-    "import com.facebook.thrift.types.Int32;" << endl << endl;
+    java_package() << endl;
 
   f_enum <<
     "public class " << tenum->get_name() << " ";
@@ -91,8 +89,8 @@
     }
 
     indent(f_enum) <<
-      "public static final Int32 " << (*c_iter)->get_name() <<
-      " = new Int32(" << value << ");" << endl;
+      "public static final int " << (*c_iter)->get_name() <<
+      " = " << value << ";" << endl;
   }
 
   scope_down(f_enum);
@@ -236,6 +234,45 @@
     indent(f_service_) <<
       "public " << function_signature(*f_iter) << " throws TException" << endl;
     scope_up(f_service_);
+    indent(f_service_) <<
+      "send_" << funname << "(";
+
+    // Get the struct of function call params
+    t_struct* arg_struct = (*f_iter)->get_arglist();
+    
+    // Declare the function arguments
+    const vector<t_field*>& fields = arg_struct->get_members();
+    vector<t_field*>::const_iterator fld_iter;
+    bool first = true;
+    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+      if (first) {
+        first = false;
+      } else {
+        f_service_ << ", ";
+      }
+      f_service_ << (*fld_iter)->get_name();
+    }
+    f_service_ << ");" << endl;
+
+    if (!(*f_iter)->is_async()) {
+      f_service_ << indent();
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        f_service_ << "return ";
+      }
+      f_service_ <<
+        "recv_" << funname << "();" << endl;
+    }
+    scope_down(f_service_);
+    f_service_ << endl;
+      
+    t_function send_function(g_program->get_void_type(),
+                             string("send_") + (*f_iter)->get_name(),
+                             (*f_iter)->get_arglist());
+
+    // Open function
+    indent(f_service_) <<
+      "public " << function_signature(&send_function) << " throws TException" << endl;
+    scope_up(f_service_);
 
     // Serialize the request
     f_service_ <<
@@ -247,7 +284,7 @@
       "new TField(\"name\", TType.STRING, 0));" << endl <<
       indent() <<
       "_oprot.writeString(_otrans, " <<
-      "new TString(\"" << funname << "\"));" << endl <<
+      "\"" << funname << "\");" << endl <<
       indent() <<
       "_oprot.writeFieldEnd(_otrans);" << endl <<
       indent() <<
@@ -266,32 +303,46 @@
     indent(f_service_) <<
       "_otrans.flush();" << endl;
 
-    // Read the response
-    t_struct result_struct((*f_iter)->get_name() + "_result");
-    t_field result_field((*f_iter)->get_returntype(), "_result");
-
-    // Add a field to the return struct if non void
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      indent(f_service_) <<
-        declare_field(&result_field, true) << endl;
-      result_struct.append(&result_field);
-    }
-
-    // Deserialize response struct
-    generate_deserialize_struct(&result_struct);
-
-    // Careful, only return _result if not a void function
-    if (!(*f_iter)->get_returntype()->is_void()) {
-      indent(f_service_) <<
-        "return _result;" << endl;
-    } else {
-      indent(f_service_) <<
-        "return;" << endl;
-    }
-
-    // Close function
     scope_down(f_service_);
     f_service_ << endl;
+
+    if (!(*f_iter)->is_async()) {
+      t_struct noargs;
+      t_function recv_function((*f_iter)->get_returntype(),
+                               string("recv_") + (*f_iter)->get_name(),
+                               &noargs);
+      // Open function
+      indent(f_service_) <<
+        "public " << function_signature(&recv_function) << " throws TException" << endl;
+      scope_up(f_service_);
+      
+      // Read the response
+      t_struct result_struct((*f_iter)->get_name() + "_result");
+      t_field result_field((*f_iter)->get_returntype(), "_result");
+      
+      // Add a field to the return struct if non void
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          declare_field(&result_field, true) << endl;
+        result_struct.append(&result_field);
+      }
+      
+      // Deserialize response struct
+      generate_deserialize_struct(&result_struct);
+      
+      // Careful, only return _result if not a void function
+      if (!(*f_iter)->get_returntype()->is_void()) {
+        indent(f_service_) <<
+          "return _result;" << endl;
+      } else {
+        indent(f_service_) <<
+          "return;" << endl;
+      }
+      
+      // Close function
+      scope_down(f_service_);
+      f_service_ << endl;
+    }
   }
 
   indent_down();
@@ -356,21 +407,21 @@
 
   f_service_ <<
     indent() <<
-    "TString _fname = new TString();" << endl <<
+    "String _fname;" << endl <<
     indent() <<
-    "TStruct _struct = new TStruct();" << endl <<
+    "TStruct _struct;" << endl <<
     indent() <<
-    "TField _field = new TField();" << endl <<
+    "TField _field;" << endl <<
     indent() <<
-    "_iprot.readStructBegin(_itrans, _struct);" << endl <<
+    "_struct = _iprot.readStructBegin(_itrans);" << endl <<
     indent() <<
-    "_iprot.readFieldBegin(_itrans, _field);" << endl <<
+    "_field = _iprot.readFieldBegin(_itrans);" << endl <<
     indent() <<
-    "_iprot.readString(_itrans, _fname);" << endl <<
+    "_fname = _iprot.readString(_itrans);" << endl <<
     indent() <<
     "_iprot.readFieldEnd(_itrans);" << endl <<
     indent() <<
-    "_iprot.readFieldBegin(_itrans, _field);" << endl;
+    "_field = _iprot.readFieldBegin(_itrans);" << endl;
 
   bool first = true;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
@@ -381,7 +432,7 @@
       first = false;
     }
     f_service_ <<
-      "if (_fname.value.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl;
+      "if (_fname.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl;
     indent_up();
     indent(f_service_) <<
       "process_" << (*f_iter)->get_name() <<
@@ -404,7 +455,7 @@
     indent() <<
     "_iprot.readFieldEnd(_itrans);" << endl <<
     indent() <<
-    "_iprot.readFieldBegin(_itrans, _field);" << endl <<   
+    "_field = _iprot.readFieldBegin(_itrans);" << endl <<   
     indent() <<
     "_iprot.readStructEnd(_itrans);" << endl <<
     indent() <<
@@ -514,7 +565,7 @@
   } else if (type->is_base_type() || type->is_enum()) {
 
     indent(f_service_) <<
-      "_iprot.";
+      name << " = _iprot.";
     
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
@@ -524,28 +575,28 @@
           name;
         break;
       case t_base_type::TYPE_STRING:        
-        f_service_ << "readString(_itrans, " << name << ");";
+        f_service_ << "readString(_itrans);";
         break;
       case t_base_type::TYPE_BYTE:
-        f_service_ << "readByte(_itrans, " << name << ");";
+        f_service_ << "readByte(_itrans);";
         break;
       case t_base_type::TYPE_I32:
-        f_service_ << "readI32(_itrans, " << name << ");";
+        f_service_ << "readI32(_itrans);";
         break;
       case t_base_type::TYPE_U32:
-        f_service_ << "readU32(_itrans, " << name << ");";
+        f_service_ << "readU32(_itrans);";
         break;
       case t_base_type::TYPE_I64:
-        f_service_ << "readI64(_itrans, " << name << ");";
+        f_service_ << "readI64(_itrans);";
         break;
       case t_base_type::TYPE_U64:
-        f_service_ << "readU64(_itrans, " << name << ");";
+        f_service_ << "readU64(_itrans);";
         break;
       default:
         throw "compiler error: no C++ name for base type " + tbase;
       }
     } else if (type->is_enum()) {
-      f_service_ << "readI32(_itrans, " << name << ");";
+      f_service_ << "readI32(_itrans);";
     }
     f_service_ <<
       endl;
@@ -574,9 +625,8 @@
   
   // Declare stack tmp variables
   f_service_ <<
-    indent() << "TStruct " << _struct << " = new TStruct();" << endl <<
-    indent() << "TField " << _field << " = new TField();" << endl <<
-    indent() << "_iprot.readStructBegin(_itrans, " << _struct << ");" << endl;
+    indent() << "TField " << _field << ";" << endl <<
+    indent() << "TStruct " << _struct << " = _iprot.readStructBegin(_itrans);" << endl;
   
   // Loop over reading in fields
   indent(f_service_) <<
@@ -586,11 +636,11 @@
     
     // Read beginning field marker
     indent(f_service_) <<
-      "_iprot.readFieldBegin(_itrans, " << _field << ");" << endl;
+      _field << " = _iprot.readFieldBegin(_itrans);" << endl;
     
     // Check for field STOP marker and break
     indent(f_service_) <<
-      "if (" << _field << ".type.equals(TType.STOP)) { " << endl;
+      "if (" << _field << ".type == TType.STOP) { " << endl;
     indent_up();
     indent(f_service_) <<
       "break;" << endl;
@@ -600,7 +650,7 @@
     
     // Switch statement on the field we are reading
     indent(f_service_) <<
-      "switch ((int)" << _field << ".id.get())" << endl;
+      "switch ((int)" << _field << ".id)" << endl;
 
       scope_up(f_service_);
     
@@ -656,16 +706,13 @@
   // Declare variables, read header
   if (ttype->is_map()) {
     f_service_ <<
-      indent() << "TMap " << obj << " = new TMap();" << endl <<
-      indent() << "_iprot.readMapBegin(_itrans, " << obj << ");" << endl;
+      indent() << "TMap " << obj << " = _iprot.readMapBegin(_itrans);" << endl;
   } else if (ttype->is_set()) {
     f_service_ <<
-      indent() << "TSet " << obj << " = new TSet();" << endl <<
-      indent() << "_iprot.readSetBegin(_itrans, " << obj << ");" << endl;
+      indent() << "TSet " << obj << " = _iprot.readSetBegin(_itrans);" << endl;
   } else if (ttype->is_list()) {
     f_service_ <<
-      indent() << "TList " << obj << " = new TList();" << endl <<
-      indent() << "_iprot.readListBegin(_itrans, " << obj << ");" << endl;
+      indent() << "TList " << obj << " = _iprot.readListBegin(_itrans);" << endl;
   }
 
 
@@ -673,7 +720,7 @@
   string i = tmp("_i");
   indent(f_service_) <<
     "for (int " << i << " = 0; " <<
-    i << " < " << obj << ".size.get()" << "; " <<
+    i << " < " << obj << ".size" << "; " <<
     "++" << i << ")" << endl;
   
     scope_up(f_service_);
@@ -853,7 +900,7 @@
       indent() <<
       _field << ".type = " << type_to_enum((*f_iter)->get_type()) << ";" << endl <<
       indent() <<
-      _field << ".id.set(" << (*f_iter)->get_key() << ");" << endl <<
+      _field << ".id = " << (*f_iter)->get_key() << ";" << endl <<
       indent() <<
       "_oprot.writeFieldBegin(_otrans, " << _field << ");" << endl;
     // Write field contents
@@ -975,28 +1022,29 @@
  * Returns a Java type name
  *
  * @param ttype The type
+ * @param container Is the type going inside a container?
  */
-string t_java_generator::type_name(t_type* ttype) {
+string t_java_generator::type_name(t_type* ttype, bool in_container) {
   // In Java typedefs are just resolved to their real type
   while (ttype->is_typedef()) {
     ttype = ((t_typedef*)ttype)->get_type();
   }
 
   if (ttype->is_base_type()) {
-    return base_type_name(((t_base_type*)ttype)->get_base());
+    return base_type_name(((t_base_type*)ttype)->get_base(), in_container);
   } else if (ttype->is_enum()) {
-    return "Int32";
+    return (in_container ? "Integer" : "int");
   } else if (ttype->is_map()) {
     t_map* tmap = (t_map*) ttype;
     return "HashMap<" +
-      type_name(tmap->get_key_type()) + "," +
-      type_name(tmap->get_val_type()) + ">";
+      type_name(tmap->get_key_type(), true) + "," +
+      type_name(tmap->get_val_type(), true) + ">";
   } else if (ttype->is_set()) {
     t_set* tset = (t_set*) ttype;
-    return "HashSet<" + type_name(tset->get_elem_type()) + ">";
+    return "HashSet<" + type_name(tset->get_elem_type(), true) + ">";
   } else if (ttype->is_list()) {
     t_list* tlist = (t_list*) ttype;
-    return "ArrayList<" + type_name(tlist->get_elem_type()) + ">";
+    return "ArrayList<" + type_name(tlist->get_elem_type(), true) + ">";
   } else {
     return ttype->get_name();
   }
@@ -1006,23 +1054,23 @@
  * Returns the C++ type that corresponds to the thrift type.
  *
  * @param tbase The base type
+ * @param container Is it going in a Java container?
  */
-string t_java_generator::base_type_name(t_base_type::t_base tbase) {
+string t_java_generator::base_type_name(t_base_type::t_base tbase,
+                                        bool in_container) {
   switch (tbase) {
   case t_base_type::TYPE_VOID:
     return "void";
   case t_base_type::TYPE_STRING:
-    return "TString";
+    return "String";
   case t_base_type::TYPE_BYTE:
-    return "UInt8";
+    return "byte";
   case t_base_type::TYPE_I32:
-    return "Int32";
   case t_base_type::TYPE_U32:
-    return "UInt32";
+    return (in_container ? "Integer" : "int");
   case t_base_type::TYPE_I64:
-    return "Int64";
   case t_base_type::TYPE_U64:
-    return "UInt64";
+    return (in_container ? "Long" : "long");
   default:
     throw "compiler error: no C++ name for base type " + tbase;
   }
@@ -1037,7 +1085,32 @@
   // TODO(mcslee): do we ever need to initialize the field?
   string result = type_name(tfield->get_type()) + " " + tfield->get_name();
   if (init) {
-    result += " = new " + type_name(tfield->get_type()) + "()";
+    t_type* ttype = tfield->get_type();
+    while (ttype->is_typedef()) {
+      ttype = ((t_typedef*)ttype)->get_type();
+    }
+    if (ttype->is_base_type()) {
+      t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
+      switch (tbase) {
+      case t_base_type::TYPE_VOID:
+        throw "NO T_VOID CONSTRUCT";
+      case t_base_type::TYPE_STRING:
+        result += " = \"\"";
+        break;
+      case t_base_type::TYPE_BYTE:
+      case t_base_type::TYPE_I32:
+      case t_base_type::TYPE_U32:
+      case t_base_type::TYPE_I64:
+      case t_base_type::TYPE_U64:
+        result += " = 0";
+        break;
+    }
+
+    } else  if (ttype->is_enum()) {
+      result += " = 0";
+    } else {
+      result += " = new " + type_name(tfield->get_type()) + "()";
+    }
   }
   return result + ";";
 }
diff --git a/compiler/src/generate/t_java_generator.h b/compiler/src/generate/t_java_generator.h
index ae96252..3dd4dbd 100644
--- a/compiler/src/generate/t_java_generator.h
+++ b/compiler/src/generate/t_java_generator.h
@@ -84,8 +84,8 @@
   std::string java_package();
   std::string java_type_imports();
   std::string java_thrift_imports();
-  std::string type_name(t_type* ttype);
-  std::string base_type_name(t_base_type::t_base tbase);
+  std::string type_name(t_type* ttype, bool in_container=false);
+  std::string base_type_name(t_base_type::t_base tbase, bool in_container=false);
   std::string declare_field(t_field* tfield, bool init=false);
   std::string function_signature(t_function* tfunction, std::string prefix="");
   std::string argument_list(t_struct* tstruct);
diff --git a/compiler/src/generate/t_php_generator.cc b/compiler/src/generate/t_php_generator.cc
index d7185ac..09a39a6 100644
--- a/compiler/src/generate/t_php_generator.cc
+++ b/compiler/src/generate/t_php_generator.cc
@@ -145,7 +145,7 @@
     php_includes();
 
   f_service_ <<
-    "require_once '" << service_name_ << "Types.php';" << endl << endl;
+    "require_once dirname(__FILE__).'/" << service_name_ << "Types.php';" << endl << endl;
 
   // Generate the three main parts of the service (well, two for now in PHP)
   generate_service_interface(tservice);
@@ -191,24 +191,41 @@
   // Private members
   f_service_ <<
     indent() << "private $_itrans = null;" << endl <<
-    indent() << "private $_otrans = null;" << endl <<
-    indent() << "private $_iprot = null;"  << endl <<
-    indent() << "private $_oprot = null;"  << endl << endl;
+    indent() << "private $_otrans = null;" << endl << endl;
+
+  if (!binary_inline_) {
+    f_service_ <<
+      indent() << "private $_iprot = null;"  << endl <<
+      indent() << "private $_oprot = null;"  << endl << endl;
+  }
 
   // Constructor function
   f_service_ <<
     indent() << "public function __construct() {" << endl <<
     indent() << "  $argv = func_get_args();" << endl <<
-    indent() << "  $argc = count($argv);" << endl <<
-    indent() << "  if ($argc == 2) {" << endl <<
-    indent() << "    $this->_itrans = $this->_otrans = $argv[0];" << endl <<
-    indent() << "    $this->_iprot = $this->_oprot = $argv[1];" << endl <<
-    indent() << "  } else if ($argc == 4) {" << endl <<
-    indent() << "    $this->_itrans = $argv[0];" << endl <<
-    indent() << "    $this->_otrans = $argv[1];" << endl <<
-    indent() << "    $this->_iprot = $argv[2];" << endl <<
-    indent() << "    $this->_oprot = $argv[3];" << endl <<
-    indent() << "  }" << endl <<
+    indent() << "  $argc = count($argv);" << endl;
+
+  if (binary_inline_) {
+    f_service_ <<
+      indent() << "  if ($argc == 1) {" << endl <<
+      indent() << "    $this->_itrans = $this->_otrans = $argv[0];" << endl <<
+      indent() << "  } else if ($argc == 2) {" << endl <<
+      indent() << "    $this->_itrans = $argv[0];" << endl <<
+      indent() << "    $this->_otrans = $argv[1];" << endl <<
+      indent() << "  }" << endl;
+  } else {
+    f_service_ <<
+      indent() << "  if ($argc == 2) {" << endl <<
+      indent() << "    $this->_itrans = $this->_otrans = $argv[0];" << endl <<
+      indent() << "    $this->_iprot = $this->_oprot = $argv[1];" << endl <<
+      indent() << "  } else if ($argc == 4) {" << endl <<
+      indent() << "    $this->_itrans = $argv[0];" << endl <<
+      indent() << "    $this->_otrans = $argv[1];" << endl <<
+      indent() << "    $this->_iprot = $argv[2];" << endl <<
+      indent() << "    $this->_oprot = $argv[3];" << endl <<
+      indent() << "  }" << endl;
+  }
+  f_service_ <<
     indent() << "}" << endl << endl;   
 
   // Generate client method implementations
@@ -222,27 +239,40 @@
       "public function " << function_signature(*f_iter) << endl;
     scope_up(f_service_);
 
-    // Serialize the request
-    f_service_ <<
-      indent() <<
-      "$this->_oprot->writeStructBegin($this->_otrans, 'function');" << endl <<
-      indent() <<
-      "$this->_oprot->writeFieldBegin($this->_otrans, 'name', TType::STRING, 0);"  << endl <<
-      indent() <<
-      "$this->_oprot->writeString($this->_otrans, '" << funname << "');" << endl <<
-      indent() <<
-      "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
-      indent() <<
-      "$this->_oprot->writeFieldBegin($this->_otrans, 'args', TType::STRUCT, 1);" << endl;
+    // Serialize the request header
+    if (binary_inline_) {
+      f_service_ <<
+        indent() << "$_output = '';" << endl <<
+        indent() << "$_output .= pack('c', TType::STRING);" << endl <<
+        indent() << "$_output .= strrev(pack('l', 0));" << endl <<
+        indent() << "$_output .= strrev(pack('l', strlen('" << funname << "')));" << endl <<
+        indent() << "$_output .= '" << funname << "';" << endl <<
+        indent() << "$_output .= pack('c', TType::STRUCT);" << endl <<
+        indent() << "$_output .= strrev(pack('l', 1));" << endl;
+    } else {
+      f_service_ <<
+        indent() << "$this->_oprot->writeStructBegin($this->_otrans, 'function');" << endl <<
+        indent() << "$this->_oprot->writeFieldBegin($this->_otrans, 'name', TType::STRING, 0);"  << endl <<
+        indent() << "$this->_oprot->writeString($this->_otrans, '" << funname << "');" << endl <<
+        indent() << "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
+        indent() << "$this->_oprot->writeFieldBegin($this->_otrans, 'args', TType::STRUCT, 1);" << endl;
+    }
+
+    // Serialize request arguments
     generate_serialize_struct((*f_iter)->get_arglist());
-    f_service_ <<
-      indent() <<
-      "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
-      indent() <<
-      "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
-      indent() <<
-      "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
-    
+
+    // Write to the stream
+    if (binary_inline_) { 
+      f_service_ <<
+        indent() << "$_output .= pack('c', TType::STOP);" << endl <<
+        indent() << "$this->_otrans->write($_output);" << endl;
+    } else {
+      f_service_ <<
+        indent() << "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
+        indent() << "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
+        indent() << "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
+    }
+      
     // Flush the request
     indent(f_service_) <<
       "$this->_otrans->flush();" << endl;
@@ -305,46 +335,99 @@
     generate_deserialize_container(tfield->get_type(), name);
   } else if (type->is_base_type() || type->is_enum()) {
 
-    indent(f_service_) <<
-      "$this->_iprot->";
-    
-    if (type->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw "compiler error: cannot serialize void field in a struct: " +
-          name;
-        break;
-      case t_base_type::TYPE_STRING:        
-        f_service_ << "readString($this->_itrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        f_service_ << "readByte($this->_itrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        f_service_ << "readI32($this->_itrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_U32:
-        f_service_ << "readU32($this->_itrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        f_service_ << "readI64($this->_itrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_U64:
-        f_service_ << "readU64($this->_itrans, $" << name << ");";
-        break;
-      default:
-        throw "compiler error: no C++ name for base type " + tbase;
+    if (binary_inline_) {
+      if (type->is_base_type()) {
+        t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+        switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw "compiler error: cannot serialize void field in a struct: " +
+            name;
+          break;
+        case t_base_type::TYPE_STRING:        
+          f_service_ <<
+            indent() << "$_len = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
+            indent() << "$_len = $_len[1];" << endl <<
+            indent() << "$" << name << " = $this->_itrans->readAll($_len);" << endl;
+          break;
+        case t_base_type::TYPE_BYTE:
+          f_service_ <<
+            indent() << "$" << name << " = unpack('c', $this->_itrans->readAll(1));" << endl <<
+            indent() << "$" << name << " = $" << name << "[1];" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          f_service_ <<
+            indent() << "$" << name << " = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
+            indent() << "$" << name << " = $" << name << "[1];" << endl;
+          break;
+        case t_base_type::TYPE_U32:
+          f_service_ << "readU32($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_I64:
+          f_service_ <<
+            indent() << "$_arr = unpack('N2', $this->_itrans->readAll(8));" << endl <<
+            indent() << "if ($_arr[1] & 0x80000000) {" << endl <<
+            indent() << "  $_arr[1] = $_arr[1] ^ 0xFFFFFFFF;" << endl <<
+            indent() << "  $_arr[2] = $_arr[2] ^ 0xFFFFFFFF;" << endl <<
+            indent() << "  $" << name << " = 0 - $_arr[1]*4294967296 - $_arr[2] - 1;" << endl <<
+            indent() << "} else {" << endl <<
+            indent() << "  $" << name << " = $_arr[1]*4294967296 + $_arr[2];" << endl <<
+            indent() << "}" << endl;
+          break;
+        case t_base_type::TYPE_U64:
+          f_service_ << "readU64($this->_itrans, $" << name << ");";
+          break;
+        default:
+          throw "compiler error: no C++ name for base type " + tbase;
+        }
+      } else if (type->is_enum()) {
+        f_service_ <<
+          indent() << "$" << name << " = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
+          indent() << "$" << name << " = $" << name << "[1];" << endl;
       }
-    } else if (type->is_enum()) {
-      f_service_ << "readI32($this->_itrans, $" << name << ");";
+
+    } else {
+
+      indent(f_service_) <<
+        "$this->_iprot->";
+      
+      if (type->is_base_type()) {
+        t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+        switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw "compiler error: cannot serialize void field in a struct: " +
+            name;
+          break;
+        case t_base_type::TYPE_STRING:        
+          f_service_ << "readString($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_BYTE:
+          f_service_ << "readByte($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_I32:
+          f_service_ << "readI32($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_U32:
+          f_service_ << "readU32($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_I64:
+          f_service_ << "readI64($this->_itrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_U64:
+          f_service_ << "readU64($this->_itrans, $" << name << ");";
+          break;
+        default:
+          throw "compiler error: no C++ name for base type " + tbase;
+        }
+      } else if (type->is_enum()) {
+        f_service_ << "readI32($this->_itrans, $" << name << ");";
+      }
+      f_service_ << endl;
     }
-    f_service_ <<
-      endl;
+
   } else {
     printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
            tfield->get_name().c_str(), type_name(type).c_str());
-  }
+  }  
 }
 
 /**
@@ -365,13 +448,20 @@
   string ftype = tmp("_ftype");
   string fname = tmp("_name");
 
-  // Declare stack tmp variables
+  t_field ffid(g_program->get_i32_type(), fid);
+  t_field fftype(g_program->get_byte_type(), ftype);
+
   f_service_ <<
     indent() << "$" << fname << " = null;" << endl <<
     indent() << "$" << ftype << " = null;" << endl <<
-    indent() << "$" << fid << " = 0;" << endl <<
-    indent() << "$this->_iprot->readStructBegin($this->_itrans, $" << fname << ");" << endl;
-  
+    indent() << "$" << fid << " = 0;" << endl;
+
+  // Declare stack tmp variables
+  if (!binary_inline_) {
+    f_service_ <<
+      indent() << "$this->_iprot->readStructBegin($this->_itrans, $" << fname << ");" << endl;   
+  }
+
   // Loop over reading in fields
   indent(f_service_) <<
     "while (true)" << endl;
@@ -379,20 +469,30 @@
     scope_up(f_service_);
     
     // Read beginning field marker
-    indent(f_service_) <<
-      "$this->_iprot->readFieldBegin($this->_itrans, " << 
-      "$" << fname << ", $" << ftype << ", $" << fid << ");" << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(&fftype);
+      f_service_ <<
+        indent() << "if ($" << ftype << " == TType::STOP) {" << endl <<
+        indent() << "  break;" << endl <<
+        indent() << "}" << endl;      
+      generate_deserialize_field(&ffid);
+    } else {
+      indent(f_service_) <<
+        "$this->_iprot->readFieldBegin($this->_itrans, " << 
+        "$" << fname << ", $" << ftype << ", $" << fid << ");" << endl;
+
+      // Check for field STOP marker and break
+      indent(f_service_) <<
+        "if ($" << ftype << " == TType::STOP) {" << endl;
+      indent_up();
+      indent(f_service_) <<
+        "break;" << endl;
+      indent_down();
+      indent(f_service_) <<
+        "}" << endl;
+    }
     
-    // Check for field STOP marker and break
-    indent(f_service_) <<
-      "if ($" << ftype << " == TType::STOP) { " << endl;
-    indent_up();
-    indent(f_service_) <<
-      "break;" << endl;
-    indent_down();
-    indent(f_service_) <<
-      "}" << endl;
-    
+   
     // Switch statement on the field we are reading
     indent(f_service_) <<
       "switch ($" << fid << ")" << endl;
@@ -417,15 +517,19 @@
         indent() <<  "  break;" << endl;
       
       scope_down(f_service_);
-
-    // Read field end marker
-    indent(f_service_) <<
-      "$this->_iprot->readFieldEnd($this->_itrans);" << endl;
+      
+    if (!binary_inline_) {
+      // Read field end marker
+      indent(f_service_) <<
+        "$this->_iprot->readFieldEnd($this->_itrans);" << endl;
+    }
     
     scope_down(f_service_);
-      
-  indent(f_service_) <<
-    "$this->_iprot->readStructEnd($this->_itrans);" << endl;
+    
+  if (!binary_inline_) {
+    indent(f_service_) <<
+      "$this->_iprot->readStructEnd($this->_itrans);" << endl;
+  }
 
   scope_down(f_service_);
 }
@@ -439,6 +543,11 @@
   string vtype = tmp("_vtype");
   string etype = tmp("_etype");
   
+  t_field fsize(g_program->get_i32_type(), size);
+  t_field fktype(g_program->get_byte_type(), ktype);
+  t_field fvtype(g_program->get_byte_type(), vtype);
+  t_field fetype(g_program->get_byte_type(), etype);
+
   indent(f_service_) <<
     "$" << size << " = 0;" << endl;
   
@@ -446,19 +555,36 @@
   if (ttype->is_map()) {
     f_service_ <<
       indent() << "$" << ktype << " = 0;" << endl <<
-      indent() << "$" << vtype << " = 0;" << endl <<
-      indent() << "$this->_iprot->readMapBegin($this->_itrans, " <<
-      "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
+      indent() << "$" << vtype << " = 0;" << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(&fktype);
+      generate_deserialize_field(&fvtype);
+      generate_deserialize_field(&fsize);
+    } else {
+      f_service_ <<
+        indent() << "$this->_iprot->readMapBegin($this->_itrans, " <<
+        "$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
+    }
   } else if (ttype->is_set()) {
-    f_service_ <<
-      indent() << "$" << etype << " = 0;" << endl <<
-      indent() << "$this->_iprot->readSetBegin($this->_itrans, " <<
-      "$" << etype << ", $" << size << ");" << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(&fetype);
+      generate_deserialize_field(&fsize);
+    } else {
+      f_service_ <<
+        indent() << "$" << etype << " = 0;" << endl <<
+        indent() << "$this->_iprot->readSetBegin($this->_itrans, " <<
+        "$" << etype << ", $" << size << ");" << endl;
+    }
   } else if (ttype->is_list()) {
-    f_service_ <<
-      indent() << "$" << etype << " = 0;" << endl <<
-      indent() << "$this->_iprot->readListBegin($this->_itrans, " <<
-      "$" << etype << ", $" << size << ");" << endl;
+    if (binary_inline_) {
+      generate_deserialize_field(&fetype);
+      generate_deserialize_field(&fsize);
+    } else {
+      f_service_ <<
+        indent() << "$" << etype << " = 0;" << endl <<
+        indent() << "$this->_iprot->readListBegin($this->_itrans, " <<
+        "$" << etype << ", $" << size << ");" << endl;
+    }
   }
 
   // For loop iterates over elements
@@ -479,13 +605,15 @@
     
     scope_down(f_service_);
 
-  // Read container end
-  if (ttype->is_map()) {
-    indent(f_service_) << "$this->_iprot->readMapEnd($this->_itrans);" << endl;
-  } else if (ttype->is_set()) {
-    indent(f_service_) << "$this->_iprot->readSetEnd($this->_itrans);" << endl;
-  } else if (ttype->is_list()) {
-    indent(f_service_) << "$this->_iprot->readListEnd($this->_itrans);" << endl;
+  if (!binary_inline_) {
+    // Read container end
+    if (ttype->is_map()) {
+      indent(f_service_) << "$this->_iprot->readMapEnd($this->_itrans);" << endl;
+    } else if (ttype->is_set()) {
+      indent(f_service_) << "$this->_iprot->readSetEnd($this->_itrans);" << endl;
+    } else if (ttype->is_list()) {
+      indent(f_service_) << "$this->_iprot->readListEnd($this->_itrans);" << endl;
+    }
   }
 
   scope_down(f_service_);
@@ -571,41 +699,84 @@
   } else if (type->is_base_type() || type->is_enum()) {
 
     string name = prefix + tfield->get_name();
-    indent(f_service_) <<
-      "$this->_oprot->";
-    
-    if (type->is_base_type()) {
-      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
-      switch (tbase) {
-      case t_base_type::TYPE_VOID:
-        throw
-          "compiler error: cannot serialize void field in a struct: " + name;
-        break;
-      case t_base_type::TYPE_STRING:
-        f_service_ << "writeString($this->_otrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_BYTE:
-        f_service_ << "writeByte($this->_otrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_I32:
-        f_service_ << "writeI32($this->_otrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_U32:
-        f_service_ << "writeU32($this->_otrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_I64:
-        f_service_ << "writeI64($this->_otrans, $" << name << ");";
-        break;
-      case t_base_type::TYPE_U64:
-        f_service_ << "writeU64($this->_otrans, $" << name << ");";
-        break;
-      default:
-        throw "compiler error: no C++ name for base type " + tbase;
+
+    if (binary_inline_) {
+      if (type->is_base_type()) {
+        t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+        switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot serialize void field in a struct: " + name;
+          break;
+        case t_base_type::TYPE_STRING:
+          f_service_ <<
+            indent() << "$_output .= strrev(pack('l', strlen($" << name << ")));" << endl <<
+            indent() << "$_output .= $" << name << ";" << endl;
+          break;
+        case t_base_type::TYPE_BYTE:
+          f_service_ <<
+            indent() << "$_output .= pack('c', $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I32:
+          f_service_ <<
+            indent() << "$_output .= strrev(pack('l', $" << name << "));" << endl;
+          break;
+        case t_base_type::TYPE_U32:
+          f_service_ <<
+            indent() << "writeU32($this->_otrans, $" << name << ");" << endl;
+          break;
+        case t_base_type::TYPE_I64:
+          f_service_ << 
+            indent() << "$_output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
+          break;
+        case t_base_type::TYPE_U64:
+          f_service_ << "writeU64($this->_otrans, $" << name << ");";
+          break;
+        default:
+          throw "compiler error: no C++ name for base type " + tbase;
+        }
+      } else if (type->is_enum()) {
+        f_service_ <<
+          indent() << "$_output .= strrev(pack('l', $" << name << "));" << endl;
       }
-    } else if (type->is_enum()) {
-      f_service_ << "writeI32($this->_otrans, $" << name << ");";
+    } else {
+
+      indent(f_service_) <<
+        "$this->_oprot->";
+      
+      if (type->is_base_type()) {
+        t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+        switch (tbase) {
+        case t_base_type::TYPE_VOID:
+          throw
+            "compiler error: cannot serialize void field in a struct: " + name;
+          break;
+        case t_base_type::TYPE_STRING:
+          f_service_ << "writeString($this->_otrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_BYTE:
+          f_service_ << "writeByte($this->_otrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_I32:
+          f_service_ << "writeI32($this->_otrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_U32:
+          f_service_ << "writeU32($this->_otrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_I64:
+          f_service_ << "writeI64($this->_otrans, $" << name << ");";
+          break;
+        case t_base_type::TYPE_U64:
+          f_service_ << "writeU64($this->_otrans, $" << name << ");";
+          break;
+        default:
+          throw "compiler error: no C++ name for base type " + tbase;
+        }
+      } else if (type->is_enum()) {
+        f_service_ << "writeI32($this->_otrans, $" << name << ");";
+      }
+      f_service_ << endl;
     }
-    f_service_ << endl;
   } else {
     printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
            prefix.c_str(),
@@ -627,25 +798,46 @@
   vector<t_field*>::const_iterator f_iter;
 
   scope_up(f_service_);
-  indent(f_service_) <<
-    "$this->_oprot->writeStructBegin($this->_otrans, '" << name << "');" << endl;
+
+  if (!binary_inline_) {
+    indent(f_service_) <<
+      "$this->_oprot->writeStructBegin($this->_otrans, '" << name << "');" << endl;
+  }
+
   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
     // Write field header
-    indent(f_service_) <<
-      "$this->_oprot->writeFieldBegin($this->_otrans, " <<
-      "'" << (*f_iter)->get_name() << "', " <<
-      type_to_enum((*f_iter)->get_type()) << ", " <<
-      (*f_iter)->get_key() << ");" << endl;
+    if (binary_inline_) {
+      f_service_ <<
+        indent() << "$_output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
+        indent() << "$_output .= strrev(pack('l', " << (*f_iter)->get_key() << "));" << endl;
+    } else {
+      indent(f_service_) <<
+        "$this->_oprot->writeFieldBegin($this->_otrans, " <<
+        "'" << (*f_iter)->get_name() << "', " <<
+        type_to_enum((*f_iter)->get_type()) << ", " <<
+        (*f_iter)->get_key() << ");" << endl;
+    }
+
     // Write field contents
     generate_serialize_field(*f_iter, prefix);
+
     // Write field closer
-    indent(f_service_) <<
-      "$this->_oprot->writeFieldEnd($this->_otrans);" << endl;
+    if (binary_inline_) {
+    } else {
+      indent(f_service_) <<
+        "$this->_oprot->writeFieldEnd($this->_otrans);" << endl;
+    }
   }
-  // Write the struct map
-  f_service_ <<
-    indent() << "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
-    indent() << "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
+
+  if (binary_inline_) {
+    f_service_ <<
+      indent() << "$_output .= pack('c', TType::STOP);" << endl;
+  } else {
+    // Write the struct map
+    f_service_ <<
+      indent() << "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
+      indent() << "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
+  }
 
   scope_down(f_service_);
 }
@@ -655,21 +847,42 @@
   scope_up(f_service_);
   
   if (ttype->is_map()) {
-    indent(f_service_) <<
-      "$this->_oprot->writeMapBegin($this->_otrans, " <<
-      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
-      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
-      "count($" << prefix << "));" << endl;
+    if (binary_inline_) {
+      f_service_ <<
+        indent() << "$_output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl <<
+        indent() << "$_output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl <<
+        indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+    } else {
+      indent(f_service_) <<
+        "$this->_oprot->writeMapBegin($this->_otrans, " <<
+        type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
+        type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
   } else if (ttype->is_set()) {
-    indent(f_service_) <<
-      "$this->_oprot->writeSetBegin($this->_otrans, " <<
-      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
-      "count($" << prefix << "));" << endl;
+    if (binary_inline_) {
+      f_service_ <<
+        indent() << "$_output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
+        indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+
+    } else {
+      indent(f_service_) <<
+        "$this->_oprot->writeSetBegin($this->_otrans, " <<
+        type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
   } else if (ttype->is_list()) {
-    indent(f_service_) <<
-      "$this->_oprot->writeListBegin($this->_otrans, " <<
-      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
-      "count($" << prefix << "));" << endl;
+    if (binary_inline_) {
+      f_service_ <<
+        indent() << "$_output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
+        indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
+
+    } else {
+      indent(f_service_) <<
+        "$this->_oprot->writeListBegin($this->_otrans, " <<
+        type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
+        "count($" << prefix << "));" << endl;
+    }
   }
 
     scope_up(f_service_);
@@ -699,6 +912,10 @@
       scope_down(f_service_);
     }
     
+ 
+    scope_down(f_service_);
+
+  if (!binary_inline_) {
     if (ttype->is_map()) {
       indent(f_service_) <<
         "$this->_oprot->writeMapEnd($this->_otrans);" << endl;
@@ -709,8 +926,7 @@
       indent(f_service_) <<
         "$this->_oprot->writeListEnd($this->_otrans);" << endl;
     }
-    
-    scope_down(f_service_);
+  }
  
   scope_down(f_service_);  
 }
diff --git a/compiler/src/generate/t_php_generator.h b/compiler/src/generate/t_php_generator.h
index d01acd2..e5fb30c 100644
--- a/compiler/src/generate/t_php_generator.h
+++ b/compiler/src/generate/t_php_generator.h
@@ -18,7 +18,10 @@
  */
 class t_php_generator : public t_oop_generator {
  public:
-  t_php_generator() {}
+  t_php_generator(bool binary_inline=false) {
+    binary_inline_ = binary_inline;
+  }
+  
   ~t_php_generator() {}
 
   /** Init and close methods */
@@ -93,6 +96,11 @@
 
   std::ofstream f_types_;
   std::ofstream f_service_;
+
+  /** Generate protocol-independent template? Or Binary inline code? */
+
+  bool binary_inline_;
+
 };
 
 #endif
diff --git a/compiler/src/main.cc b/compiler/src/main.cc
index 8783309..6a7faf8 100644
--- a/compiler/src/main.cc
+++ b/compiler/src/main.cc
@@ -98,6 +98,7 @@
   fprintf(stderr, "  -cpp    Generate C++ output files\n");
   fprintf(stderr, "  -java   Generate Java output files\n");
   fprintf(stderr, "  -php    Generate PHP output files\n");
+  fprintf(stderr, "  -phpi   Generate PHP inlined files\n");
   //fprintf(stderr, "  -python Generate Python output files\n");
   fprintf(stderr, "  -d      Print parse debugging to standard output\n");
   exit(1);
@@ -111,6 +112,7 @@
   bool gen_cpp = false;
   bool gen_java = false;
   bool gen_php = false;
+  bool php_inline = false;
 
   // Setup time string
   time_t now = time(NULL);
@@ -130,6 +132,10 @@
       gen_java = true;
     } else if (strcmp(argv[i], "-php") == 0) {
       gen_php = true;
+      php_inline = false;
+    } else if (strcmp(argv[i], "-phpi") == 0) {
+      gen_php = true;
+      php_inline = true;
     } else {
       fprintf(stderr, "!!! Unrecognized option: %s\n", argv[i]);
       usage();
@@ -181,7 +187,7 @@
     }
 
     if (gen_php) {
-      t_php_generator* php = new t_php_generator();
+      t_php_generator* php = new t_php_generator(php_inline);
       php->generate_program(g_program);
       delete php;
     }
diff --git a/compiler/src/parse/t_function.h b/compiler/src/parse/t_function.h
index b248db7..9e6c56a 100644
--- a/compiler/src/parse/t_function.h
+++ b/compiler/src/parse/t_function.h
@@ -7,26 +7,33 @@
 
 /**
  * Representation of a function. Key parst are return type, function name,
- * optional modifiers, and an argument list. Each function also has a
- * hash signature that is used in the network protocol.
+ * optional modifiers, and an argument list.
  *
  * @author Mark Slee <mcslee@facebook.com>
  */
 class t_function {
  public:
-  t_function(t_type* returntype, std::string name, t_struct* arglist) :
-    returntype_(returntype), name_(name), arglist_(arglist) {}
+  t_function(t_type* returntype,
+             std::string name,
+             t_struct* arglist,
+             bool async=false) :
+    returntype_(returntype),
+    name_(name),
+    arglist_(arglist),
+    async_(async) {}
 
   ~t_function() {}
 
   t_type*      get_returntype() const { return returntype_; }
   const std::string& get_name() const { return name_; }
   t_struct*    get_arglist()    const { return arglist_; }
+  bool         is_async()       const { return async_; }
 
  private:
   t_type* returntype_;
   std::string name_;
   t_struct* arglist_;
+  bool async_;
 };
 
 #endif
diff --git a/compiler/src/thrift.l b/compiler/src/thrift.l
index 33cbda8..9d2944a 100644
--- a/compiler/src/thrift.l
+++ b/compiler/src/thrift.l
@@ -33,6 +33,7 @@
 
 {symbol}      { return yytext[0];   }
 
+"void"        { return tok_void;     }
 "byte"        { return tok_byte;     }
 "string"      { return tok_string;   }
 "i32"         { return tok_i32;      }
@@ -44,7 +45,6 @@
 "list"        { return tok_list;     }
 "set"         { return tok_set;      }
 
-"void"        { return tok_void;     }
 "async"       { return tok_async;    }
 
 "typedef"     { return tok_typedef;  }
@@ -52,6 +52,7 @@
 "service"     { return tok_service;  }
 "enum"        { return tok_enum;     }
 
+
 {intconstant} { yylval.iconst = atoi(yytext) ; return tok_int_constant; }
 {identifier}  { yylval.id = strdup(yytext); return tok_identifier; }
 
diff --git a/compiler/src/thrift.y b/compiler/src/thrift.y
index 269d163..d0882ff 100644
--- a/compiler/src/thrift.y
+++ b/compiler/src/thrift.y
@@ -20,6 +20,7 @@
 %union {
   char*       id;
   int         iconst;
+  bool        tbool;
   t_type*     ttype;
   t_typedef*  ttypedef;
   t_enum*     tenum;
@@ -82,10 +83,11 @@
 %type<tservice>  Service
 
 %type<tfunction> Function
-%type<id>        FunctionModifiers
 %type<ttype>     FunctionType
 %type<tservice>  FunctionList
 
+%type<tbool>     AsyncOptional
+
 %%
 
 /** Thrift Grammar */
@@ -210,17 +212,21 @@
     }
 
 Function:
-  FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
+  FunctionType AsyncOptional tok_identifier '(' FieldList ')'
     {
       $5->set_name(std::string($3) + "_args");
-      $$ = new t_function($1, $3, $5);
+      $$ = new t_function($1, $3, $5, $2);
       y_field_val = 0;
     }
 
-FunctionModifiers:
+AsyncOptional:
+  tok_async
     {
-      /** TODO(mcslee): implement async modifier, etc. */
-      $$ = 0;
+      $$ = true;
+    }
+|
+    {
+      $$ = false;
     }
 
 FieldList: