├── .gitignore ├── tests ├── tars2php.sh ├── protobuf │ ├── proto2php.sh │ ├── server │ │ ├── protocol │ │ │ └── PHPTest │ │ │ │ └── PHPPbServer │ │ │ │ ├── GreeterServant.php │ │ │ │ └── tars │ │ │ │ └── helloworld.proto │ │ ├── GPBMetadata │ │ │ └── Helloworld.php │ │ └── Helloworld │ │ │ ├── HelloRequest.php │ │ │ └── HelloReply.php │ ├── tars.proto.php │ ├── tarsclient.proto.php │ ├── helloworld.proto │ └── client │ │ ├── GPBMetadata │ │ └── Helloworld.php │ │ ├── protocol │ │ └── PHPTest │ │ │ └── PHPPbServer │ │ │ ├── tars │ │ │ └── helloworld.proto │ │ │ └── GreeterServant.php │ │ └── Helloworld │ │ ├── HelloRequest.php │ │ └── HelloReply.php ├── tars.proto.php ├── tarsclient.proto.php ├── test.tars ├── server │ └── PHPTest │ │ └── PHPServer │ │ └── obj │ │ ├── classes │ │ ├── SimpleStruct.php │ │ ├── OutStruct.php │ │ ├── ComplicatedStruct.php │ │ └── LotofTags.php │ │ ├── tars │ │ └── example.tars │ │ └── TestTafServiceServant.php ├── client │ └── PHPTest │ │ └── PHPServer │ │ └── obj │ │ ├── classes │ │ ├── SimpleStruct.php │ │ ├── OutStruct.php │ │ ├── ComplicatedStruct.php │ │ └── LotofTags.php │ │ ├── tars │ │ └── example.tars │ │ └── TestTafServiceServant.php └── example.tars ├── composer.json ├── README.zh.md ├── README.md └── src ├── proto2php.php └── tars2php.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | .idea -------------------------------------------------------------------------------- /tests/tars2php.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | php ../src/tars2php.php tarsclient.proto.php 4 | 5 | php ../src/tars2php.php tars.proto.php 6 | -------------------------------------------------------------------------------- /tests/protobuf/proto2php.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | php ../../src/proto2php.php tars.proto.php 4 | 5 | php ../../src/proto2php.php tarsclient.proto.php 6 | -------------------------------------------------------------------------------- /tests/protobuf/server/protocol/PHPTest/PHPPbServer/GreeterServant.php: -------------------------------------------------------------------------------- 1 | 'PHPTest', 11 | 'serverName' => 'PHPServer', 12 | 'objName' => 'obj', 13 | 'withServant' => true, //决定是服务端,还是客户端的自动生成 14 | 'tarsFiles' => array( 15 | './example.tars', 16 | ), 17 | 'dstPath' => './server/', 18 | 'namespacePrefix' => 'Server\servant', 19 | ); 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phptars/tars2php", 3 | "description": "php代码自动生成工具", 4 | "version":"0.3.2", 5 | "authors": [ 6 | { 7 | "name": "Chen Liang", 8 | "email": "liangchen@yuewen.com" 9 | }, 10 | { 11 | "name": "Yong Zhang", 12 | "email": "bob_zy@yeah.net" 13 | } 14 | ], 15 | "minimum-stability": "dev", 16 | "require": { 17 | "php": ">=5.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/tarsclient.proto.php: -------------------------------------------------------------------------------- 1 | 'PHPTest', 11 | 'serverName' => 'PHPServer', 12 | 'objName' => 'obj', 13 | 'withServant' => false, //决定是服务端,还是客户端的自动生成 14 | 'tarsFiles' => array( 15 | './example.tars', 16 | ), 17 | 'dstPath' => './client/', 18 | 'namespacePrefix' => 'ClientServer\servant', 19 | ); 20 | -------------------------------------------------------------------------------- /tests/protobuf/tars.proto.php: -------------------------------------------------------------------------------- 1 | 'PHPTest', 11 | 'serverName' => 'PHPPbServer', 12 | 'objName' => 'obj', 13 | 'withServant' => true, //决定是服务端,还是客户端的自动生成 14 | 'tarsFiles' => array( 15 | './helloworld.proto', 16 | ), 17 | 'dstPath' => './server/protocol', //这里指定的是 impl 基础interface 生成的位置 18 | 'protocDstPath' => './server', //这里指定的是 protoc 生成的问题 19 | 'namespacePrefix' => 'Protocol', 20 | ); 21 | -------------------------------------------------------------------------------- /tests/protobuf/tarsclient.proto.php: -------------------------------------------------------------------------------- 1 | 'PHPTest', 11 | 'serverName' => 'PHPPbServer', 12 | 'objName' => 'obj', 13 | 'withServant' => false, //决定是服务端,还是客户端的自动生成 14 | 'tarsFiles' => array( 15 | './helloworld.proto', 16 | ), 17 | 'dstPath' => './client/protocol', //这里指定的是 impl 基础interface 生成的位置 18 | 'protocDstPath' => './client', //这里指定的是 protoc 生成的问题 19 | 'namespacePrefix' => 'Protocol', 20 | ); 21 | -------------------------------------------------------------------------------- /tests/test.tars: -------------------------------------------------------------------------------- 1 | module testservant 2 | { 3 | enum GoodType { 4 | TYPE_ONE = 1, 5 | TYPE_TWO = 2, 6 | TYPE_THREE = 3 7 | }; 8 | 9 | struct Foo { 10 | 0 optional GoodType goodType; 11 | 1 optional map goodTypeMap; 12 | 2 optional vector goodTypeList; 13 | 3 optional map> goodMap; 14 | }; 15 | 16 | interface TestService 17 | { 18 | GoodType testFoo(GoodType goodType, Map goodTypeMap, Map intMap, out Foo foo, out GoodType goodTypeRet); 19 | }; 20 | 21 | } -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/classes/SimpleStruct.php: -------------------------------------------------------------------------------- 1 | array( 18 | 'name'=>'id', 19 | 'required'=>true, 20 | 'type'=>\TARS::INT64, 21 | ), 22 | self::COUNT => array( 23 | 'name'=>'count', 24 | 'required'=>true, 25 | 'type'=>\TARS::UINT32, 26 | ), 27 | self::PAGE => array( 28 | 'name'=>'page', 29 | 'required'=>true, 30 | 'type'=>\TARS::SHORT, 31 | ), 32 | ); 33 | 34 | public function __construct() { 35 | parent::__construct('PHPTest_PHPServer_obj_SimpleStruct', self::$_fields); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/classes/SimpleStruct.php: -------------------------------------------------------------------------------- 1 | array( 18 | 'name'=>'id', 19 | 'required'=>true, 20 | 'type'=>\TARS::INT64, 21 | ), 22 | self::COUNT => array( 23 | 'name'=>'count', 24 | 'required'=>true, 25 | 'type'=>\TARS::UINT32, 26 | ), 27 | self::PAGE => array( 28 | 'name'=>'page', 29 | 'required'=>true, 30 | 'type'=>\TARS::SHORT, 31 | ), 32 | ); 33 | 34 | public function __construct() { 35 | parent::__construct('PHPTest_PHPServer_obj_SimpleStruct', self::$_fields); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/classes/OutStruct.php: -------------------------------------------------------------------------------- 1 | array( 20 | 'name'=>'id', 21 | 'required'=>true, 22 | 'type'=>\TARS::INT64, 23 | ), 24 | self::COUNT => array( 25 | 'name'=>'count', 26 | 'required'=>true, 27 | 'type'=>\TARS::INT32, 28 | ), 29 | self::PAGE => array( 30 | 'name'=>'page', 31 | 'required'=>true, 32 | 'type'=>\TARS::SHORT, 33 | ), 34 | self::STR => array( 35 | 'name'=>'str', 36 | 'required'=>false, 37 | 'type'=>\TARS::STRING, 38 | ), 39 | ); 40 | 41 | public function __construct() { 42 | parent::__construct('PHPTest_PHPServer_obj_OutStruct', self::$_fields); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/classes/OutStruct.php: -------------------------------------------------------------------------------- 1 | array( 20 | 'name'=>'id', 21 | 'required'=>true, 22 | 'type'=>\TARS::INT64, 23 | ), 24 | self::COUNT => array( 25 | 'name'=>'count', 26 | 'required'=>true, 27 | 'type'=>\TARS::INT32, 28 | ), 29 | self::PAGE => array( 30 | 'name'=>'page', 31 | 'required'=>true, 32 | 'type'=>\TARS::SHORT, 33 | ), 34 | self::STR => array( 35 | 'name'=>'str', 36 | 'required'=>false, 37 | 'type'=>\TARS::STRING, 38 | ), 39 | ); 40 | 41 | public function __construct() { 42 | parent::__construct('PHPTest_PHPServer_obj_OutStruct', self::$_fields); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/classes/ComplicatedStruct.php: -------------------------------------------------------------------------------- 1 | array( 20 | 'name'=>'ss', 21 | 'required'=>true, 22 | 'type'=>\TARS::VECTOR, 23 | ), 24 | self::RS => array( 25 | 'name'=>'rs', 26 | 'required'=>true, 27 | 'type'=>\TARS::STRUCT, 28 | ), 29 | self::MSS => array( 30 | 'name'=>'mss', 31 | 'required'=>true, 32 | 'type'=>\TARS::MAP, 33 | ), 34 | self::STR => array( 35 | 'name'=>'str', 36 | 'required'=>false, 37 | 'type'=>\TARS::STRING, 38 | ), 39 | ); 40 | 41 | public function __construct() { 42 | parent::__construct('PHPTest_PHPServer_obj_ComplicatedStruct', self::$_fields); 43 | $this->rs = new SimpleStruct(); 44 | $this->ss = new \TARS_Vector(new SimpleStruct()); 45 | $this->mss = new \TARS_Map(\TARS::STRING,new SimpleStruct()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/classes/ComplicatedStruct.php: -------------------------------------------------------------------------------- 1 | array( 20 | 'name'=>'ss', 21 | 'required'=>true, 22 | 'type'=>\TARS::VECTOR, 23 | ), 24 | self::RS => array( 25 | 'name'=>'rs', 26 | 'required'=>true, 27 | 'type'=>\TARS::STRUCT, 28 | ), 29 | self::MSS => array( 30 | 'name'=>'mss', 31 | 'required'=>true, 32 | 'type'=>\TARS::MAP, 33 | ), 34 | self::STR => array( 35 | 'name'=>'str', 36 | 'required'=>false, 37 | 'type'=>\TARS::STRING, 38 | ), 39 | ); 40 | 41 | public function __construct() { 42 | parent::__construct('PHPTest_PHPServer_obj_ComplicatedStruct', self::$_fields); 43 | $this->rs = new SimpleStruct(); 44 | $this->ss = new \TARS_Vector(new SimpleStruct()); 45 | $this->mss = new \TARS_Map(\TARS::STRING,new SimpleStruct()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/protobuf/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | service Greeter { 25 | rpc SayHello(HelloRequest) returns (HelloReply) {}; 26 | } 27 | 28 | // The request message containing the user's name. 29 | message HelloRequest { 30 | string name = 1; 31 | } 32 | 33 | // The response message containing the greetings 34 | message HelloReply { 35 | string message = 1; 36 | } 37 | -------------------------------------------------------------------------------- /tests/protobuf/client/GPBMetadata/Helloworld.php: -------------------------------------------------------------------------------- 1 | internalAddGeneratedFile(hex2bin( 18 | "0ae6010a1068656c6c6f776f726c642e70726f746f120a68656c6c6f776f" . 19 | "726c64221c0a0c48656c6c6f52657175657374120c0a046e616d65180120" . 20 | "012809221d0a0a48656c6c6f5265706c79120f0a076d6573736167651801" . 21 | "2001280932490a0747726565746572123e0a0853617948656c6c6f12182e" . 22 | "68656c6c6f776f726c642e48656c6c6f526571756573741a162e68656c6c" . 23 | "6f776f726c642e48656c6c6f5265706c79220042360a1b696f2e67727063" . 24 | "2e6578616d706c65732e68656c6c6f776f726c64420f48656c6c6f576f72" . 25 | "6c6450726f746f5001a20203484c57620670726f746f33" 26 | ), true); 27 | 28 | static::$is_initialized = true; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /tests/protobuf/server/GPBMetadata/Helloworld.php: -------------------------------------------------------------------------------- 1 | internalAddGeneratedFile(hex2bin( 18 | "0ae6010a1068656c6c6f776f726c642e70726f746f120a68656c6c6f776f" . 19 | "726c64221c0a0c48656c6c6f52657175657374120c0a046e616d65180120" . 20 | "012809221d0a0a48656c6c6f5265706c79120f0a076d6573736167651801" . 21 | "2001280932490a0747726565746572123e0a0853617948656c6c6f12182e" . 22 | "68656c6c6f776f726c642e48656c6c6f526571756573741a162e68656c6c" . 23 | "6f776f726c642e48656c6c6f5265706c79220042360a1b696f2e67727063" . 24 | "2e6578616d706c65732e68656c6c6f776f726c64420f48656c6c6f576f72" . 25 | "6c6450726f746f5001a20203484c57620670726f746f33" 26 | ), true); 27 | 28 | static::$is_initialized = true; 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /tests/protobuf/client/protocol/PHPTest/PHPPbServer/tars/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | service Greeter { 25 | rpc SayHello(HelloRequest) returns (HelloReply) {}; 26 | } 27 | 28 | // The request message containing the user's name. 29 | message HelloRequest { 30 | string name = 1; 31 | } 32 | 33 | // The response message containing the greetings 34 | message HelloReply { 35 | string message = 1; 36 | } 37 | -------------------------------------------------------------------------------- /tests/protobuf/server/protocol/PHPTest/PHPPbServer/tars/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | option java_multiple_files = true; 18 | option java_package = "io.grpc.examples.helloworld"; 19 | option java_outer_classname = "HelloWorldProto"; 20 | option objc_class_prefix = "HLW"; 21 | 22 | package helloworld; 23 | 24 | service Greeter { 25 | rpc SayHello(HelloRequest) returns (HelloReply) {}; 26 | } 27 | 28 | // The request message containing the user's name. 29 | message HelloRequest { 30 | string name = 1; 31 | } 32 | 33 | // The response message containing the greetings 34 | message HelloReply { 35 | string message = 1; 36 | } 37 | -------------------------------------------------------------------------------- /tests/protobuf/client/Helloworld/HelloRequest.php: -------------------------------------------------------------------------------- 1 | helloworld.HelloRequest 15 | */ 16 | class HelloRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Generated from protobuf field string name = 1; 20 | */ 21 | private $name = ''; 22 | 23 | /** 24 | * Constructor. 25 | * 26 | * @param array $data { 27 | * Optional. Data for populating the Message object. 28 | * 29 | * @type string $name 30 | * } 31 | */ 32 | public function __construct($data = NULL) { 33 | \GPBMetadata\Helloworld::initOnce(); 34 | parent::__construct($data); 35 | } 36 | 37 | /** 38 | * Generated from protobuf field string name = 1; 39 | * @return string 40 | */ 41 | public function getName() 42 | { 43 | return $this->name; 44 | } 45 | 46 | /** 47 | * Generated from protobuf field string name = 1; 48 | * @param string $var 49 | * @return $this 50 | */ 51 | public function setName($var) 52 | { 53 | GPBUtil::checkString($var, True); 54 | $this->name = $var; 55 | 56 | return $this; 57 | } 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/protobuf/server/Helloworld/HelloRequest.php: -------------------------------------------------------------------------------- 1 | helloworld.HelloRequest 15 | */ 16 | class HelloRequest extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Generated from protobuf field string name = 1; 20 | */ 21 | private $name = ''; 22 | 23 | /** 24 | * Constructor. 25 | * 26 | * @param array $data { 27 | * Optional. Data for populating the Message object. 28 | * 29 | * @type string $name 30 | * } 31 | */ 32 | public function __construct($data = NULL) { 33 | \GPBMetadata\Helloworld::initOnce(); 34 | parent::__construct($data); 35 | } 36 | 37 | /** 38 | * Generated from protobuf field string name = 1; 39 | * @return string 40 | */ 41 | public function getName() 42 | { 43 | return $this->name; 44 | } 45 | 46 | /** 47 | * Generated from protobuf field string name = 1; 48 | * @param string $var 49 | * @return $this 50 | */ 51 | public function setName($var) 52 | { 53 | GPBUtil::checkString($var, True); 54 | $this->name = $var; 55 | 56 | return $this; 57 | } 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/protobuf/client/protocol/PHPTest/PHPPbServer/GreeterServant.php: -------------------------------------------------------------------------------- 1 | setServantName($this->_servantName); 21 | $this->_communicator = new Communicator($config); 22 | $this->_iTimeout = empty($config->getAsyncInvokeTimeout())?2:$config->getAsyncInvokeTimeout(); 23 | } catch (\Exception $e) { 24 | throw $e; 25 | } 26 | } 27 | 28 | public function SayHello(HelloRequest $inParam,HelloReply &$outParam) 29 | { 30 | try { 31 | $requestPacket = new GrpcRequestPacket(); 32 | $requestPacket->_funcName = __FUNCTION__; 33 | $requestPacket->_servantName = $this->_servantName; 34 | $requestPacket->_basePath = $this->_basePath; 35 | $requestPacket->_sBuffer = $inParam->serializeToString(); 36 | 37 | $responsePacket = new GrpcResponsePacket(); 38 | $sBuffer = $this->_communicator->invoke($requestPacket, $this->_iTimeout, $responsePacket); 39 | 40 | $outParam = new HelloReply(); 41 | $outParam->mergeFromString($sBuffer); 42 | } 43 | catch (\Exception $e) { 44 | throw $e; 45 | } 46 | } 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/classes/LotofTags.php: -------------------------------------------------------------------------------- 1 | array( 26 | 'name'=>'id', 27 | 'required'=>true, 28 | 'type'=>\TARS::INT64, 29 | ), 30 | self::COUNT => array( 31 | 'name'=>'count', 32 | 'required'=>true, 33 | 'type'=>\TARS::INT32, 34 | ), 35 | self::PAGE => array( 36 | 'name'=>'page', 37 | 'required'=>true, 38 | 'type'=>\TARS::SHORT, 39 | ), 40 | self::STR => array( 41 | 'name'=>'str', 42 | 'required'=>false, 43 | 'type'=>\TARS::STRING, 44 | ), 45 | self::SS => array( 46 | 'name'=>'ss', 47 | 'required'=>true, 48 | 'type'=>\TARS::VECTOR, 49 | ), 50 | self::RS => array( 51 | 'name'=>'rs', 52 | 'required'=>true, 53 | 'type'=>\TARS::STRUCT, 54 | ), 55 | self::MSS => array( 56 | 'name'=>'mss', 57 | 'required'=>true, 58 | 'type'=>\TARS::MAP, 59 | ), 60 | ); 61 | 62 | public function __construct() { 63 | parent::__construct('PHPTest_PHPServer_obj_LotofTags', self::$_fields); 64 | $this->rs = new SimpleStruct(); 65 | $this->ss = new \TARS_Vector(new SimpleStruct()); 66 | $this->mss = new \TARS_Map(\TARS::STRING,new SimpleStruct()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/classes/LotofTags.php: -------------------------------------------------------------------------------- 1 | array( 26 | 'name'=>'id', 27 | 'required'=>true, 28 | 'type'=>\TARS::INT64, 29 | ), 30 | self::COUNT => array( 31 | 'name'=>'count', 32 | 'required'=>true, 33 | 'type'=>\TARS::INT32, 34 | ), 35 | self::PAGE => array( 36 | 'name'=>'page', 37 | 'required'=>true, 38 | 'type'=>\TARS::SHORT, 39 | ), 40 | self::STR => array( 41 | 'name'=>'str', 42 | 'required'=>false, 43 | 'type'=>\TARS::STRING, 44 | ), 45 | self::SS => array( 46 | 'name'=>'ss', 47 | 'required'=>true, 48 | 'type'=>\TARS::VECTOR, 49 | ), 50 | self::RS => array( 51 | 'name'=>'rs', 52 | 'required'=>true, 53 | 'type'=>\TARS::STRUCT, 54 | ), 55 | self::MSS => array( 56 | 'name'=>'mss', 57 | 'required'=>true, 58 | 'type'=>\TARS::MAP, 59 | ), 60 | ); 61 | 62 | public function __construct() { 63 | parent::__construct('PHPTest_PHPServer_obj_LotofTags', self::$_fields); 64 | $this->rs = new SimpleStruct(); 65 | $this->ss = new \TARS_Vector(new SimpleStruct()); 66 | $this->mss = new \TARS_Map(\TARS::STRING,new SimpleStruct()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tests/protobuf/client/Helloworld/HelloReply.php: -------------------------------------------------------------------------------- 1 | helloworld.HelloReply 15 | */ 16 | class HelloReply extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Generated from protobuf field string message = 1; 20 | */ 21 | private $message = ''; 22 | 23 | /** 24 | * Constructor. 25 | * 26 | * @param array $data { 27 | * Optional. Data for populating the Message object. 28 | * 29 | * @type string $message 30 | * } 31 | */ 32 | public function __construct($data = NULL) { 33 | \GPBMetadata\Helloworld::initOnce(); 34 | parent::__construct($data); 35 | } 36 | 37 | /** 38 | * Generated from protobuf field string message = 1; 39 | * @return string 40 | */ 41 | public function getMessage() 42 | { 43 | return $this->message; 44 | } 45 | 46 | /** 47 | * Generated from protobuf field string message = 1; 48 | * @param string $var 49 | * @return $this 50 | */ 51 | public function setMessage($var) 52 | { 53 | GPBUtil::checkString($var, True); 54 | $this->message = $var; 55 | 56 | return $this; 57 | } 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/protobuf/server/Helloworld/HelloReply.php: -------------------------------------------------------------------------------- 1 | helloworld.HelloReply 15 | */ 16 | class HelloReply extends \Google\Protobuf\Internal\Message 17 | { 18 | /** 19 | * Generated from protobuf field string message = 1; 20 | */ 21 | private $message = ''; 22 | 23 | /** 24 | * Constructor. 25 | * 26 | * @param array $data { 27 | * Optional. Data for populating the Message object. 28 | * 29 | * @type string $message 30 | * } 31 | */ 32 | public function __construct($data = NULL) { 33 | \GPBMetadata\Helloworld::initOnce(); 34 | parent::__construct($data); 35 | } 36 | 37 | /** 38 | * Generated from protobuf field string message = 1; 39 | * @return string 40 | */ 41 | public function getMessage() 42 | { 43 | return $this->message; 44 | } 45 | 46 | /** 47 | * Generated from protobuf field string message = 1; 48 | * @param string $var 49 | * @return $this 50 | */ 51 | public function setMessage($var) 52 | { 53 | GPBUtil::checkString($var, True); 54 | $this->message = $var; 55 | 56 | return $this; 57 | } 58 | 59 | } 60 | 61 | -------------------------------------------------------------------------------- /tests/example.tars: -------------------------------------------------------------------------------- 1 | module testtafserviceservant 2 | { 3 | struct SimpleStruct { 4 | 0 require long id=0; 5 | 1 require unsigned int count=0; 6 | 2 require short page=0; 7 | }; 8 | 9 | struct OutStruct { 10 | 0 require long id=0; 11 | 1 require int count=0; 12 | 2 require short page=0; 13 | 3 optional string str; 14 | }; 15 | 16 | struct ComplicatedStruct { 17 | 0 require vector ss; 18 | 1 require SimpleStruct rs; 19 | 2 require map mss; 20 | 3 optional string str; 21 | } 22 | 23 | struct LotofTags { 24 | 0 require long id=0; 25 | 1 require int count=0; 26 | 2 require short page=0; 27 | 3 optional string str; 28 | 4 require vector ss; 29 | 5 require SimpleStruct rs; 30 | 6 require map mss; 31 | } 32 | 33 | interface TestTafService 34 | { 35 | 36 | void testTafServer (); 37 | 38 | int testLofofTags( LotofTags tags, out LotofTags outtags); 39 | 40 | void sayHelloWorld(string name, out string outGreetings); 41 | 42 | int testBasic(bool a, int b, string c, out bool d, out int e, out string f); 43 | 44 | string testStruct(long a, SimpleStruct b, out OutStruct d); 45 | 46 | string testMap( short a, SimpleStruct b, map m1, out OutStruct d, out map m2); 47 | 48 | string testVector( int a, vector v1, vector v2, out vector v3, out vector v4); 49 | 50 | SimpleStruct testReturn(); 51 | 52 | map testReturn2(); 53 | 54 | vector testComplicatedStruct(ComplicatedStruct cs,vector vcs, out ComplicatedStruct ocs,out vector ovcs); 55 | 56 | map testComplicatedMap(map mcs, out map omcs); 57 | 58 | int testEmpty(short a,out bool b1, out int in2, out OutStruct d, out vector v3,out vector v4); 59 | 60 | int testSelf(); 61 | 62 | int testProperty(); 63 | 64 | }; 65 | 66 | } -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/tars/example.tars: -------------------------------------------------------------------------------- 1 | module testtafserviceservant 2 | { 3 | struct SimpleStruct { 4 | 0 require long id=0; 5 | 1 require unsigned int count=0; 6 | 2 require short page=0; 7 | }; 8 | 9 | struct OutStruct { 10 | 0 require long id=0; 11 | 1 require int count=0; 12 | 2 require short page=0; 13 | 3 optional string str; 14 | }; 15 | 16 | struct ComplicatedStruct { 17 | 0 require vector ss; 18 | 1 require SimpleStruct rs; 19 | 2 require map mss; 20 | 3 optional string str; 21 | } 22 | 23 | struct LotofTags { 24 | 0 require long id=0; 25 | 1 require int count=0; 26 | 2 require short page=0; 27 | 3 optional string str; 28 | 4 require vector ss; 29 | 5 require SimpleStruct rs; 30 | 6 require map mss; 31 | } 32 | 33 | interface TestTafService 34 | { 35 | 36 | void testTafServer (); 37 | 38 | int testLofofTags( LotofTags tags, out LotofTags outtags); 39 | 40 | void sayHelloWorld(string name, out string outGreetings); 41 | 42 | int testBasic(bool a, int b, string c, out bool d, out int e, out string f); 43 | 44 | string testStruct(long a, SimpleStruct b, out OutStruct d); 45 | 46 | string testMap( short a, SimpleStruct b, map m1, out OutStruct d, out map m2); 47 | 48 | string testVector( int a, vector v1, vector v2, out vector v3, out vector v4); 49 | 50 | SimpleStruct testReturn(); 51 | 52 | map testReturn2(); 53 | 54 | vector testComplicatedStruct(ComplicatedStruct cs,vector vcs, out ComplicatedStruct ocs,out vector ovcs); 55 | 56 | map testComplicatedMap(map mcs, out map omcs); 57 | 58 | int testEmpty(short a,out bool b1, out int in2, out OutStruct d, out vector v3,out vector v4); 59 | 60 | int testSelf(); 61 | 62 | int testProperty(); 63 | 64 | }; 65 | 66 | } -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/tars/example.tars: -------------------------------------------------------------------------------- 1 | module testtafserviceservant 2 | { 3 | struct SimpleStruct { 4 | 0 require long id=0; 5 | 1 require unsigned int count=0; 6 | 2 require short page=0; 7 | }; 8 | 9 | struct OutStruct { 10 | 0 require long id=0; 11 | 1 require int count=0; 12 | 2 require short page=0; 13 | 3 optional string str; 14 | }; 15 | 16 | struct ComplicatedStruct { 17 | 0 require vector ss; 18 | 1 require SimpleStruct rs; 19 | 2 require map mss; 20 | 3 optional string str; 21 | } 22 | 23 | struct LotofTags { 24 | 0 require long id=0; 25 | 1 require int count=0; 26 | 2 require short page=0; 27 | 3 optional string str; 28 | 4 require vector ss; 29 | 5 require SimpleStruct rs; 30 | 6 require map mss; 31 | } 32 | 33 | interface TestTafService 34 | { 35 | 36 | void testTafServer (); 37 | 38 | int testLofofTags( LotofTags tags, out LotofTags outtags); 39 | 40 | void sayHelloWorld(string name, out string outGreetings); 41 | 42 | int testBasic(bool a, int b, string c, out bool d, out int e, out string f); 43 | 44 | string testStruct(long a, SimpleStruct b, out OutStruct d); 45 | 46 | string testMap( short a, SimpleStruct b, map m1, out OutStruct d, out map m2); 47 | 48 | string testVector( int a, vector v1, vector v2, out vector v3, out vector v4); 49 | 50 | SimpleStruct testReturn(); 51 | 52 | map testReturn2(); 53 | 54 | vector testComplicatedStruct(ComplicatedStruct cs,vector vcs, out ComplicatedStruct ocs,out vector ovcs); 55 | 56 | map testComplicatedMap(map mcs, out map omcs); 57 | 58 | int testEmpty(short a,out bool b1, out int in2, out OutStruct d, out vector v3,out vector v4); 59 | 60 | int testSelf(); 61 | 62 | int testProperty(); 63 | 64 | }; 65 | 66 | } -------------------------------------------------------------------------------- /tests/server/PHPTest/PHPServer/obj/TestTafServiceServant.php: -------------------------------------------------------------------------------- 1 | \TARS::BOOL 11 | char => \TARS::CHAR 12 | uint8 => \TARS::UINT8 13 | short => \TARS::SHORT 14 | uint16 => \TARS::UINT16 15 | float => \TARS::FLOAT 16 | double => \TARS::DOUBLE 17 | int32 => \TARS::INT32 18 | uint32 => \TARS::UINT32 19 | int64 => \TARS::INT64 20 | string => \TARS::STRING 21 | vector => \TARS::VECTOR 22 | map => \TARS::MAP 23 | struct => \TARS::STRUCT 24 | ``` 25 | 当我们需要标识具体的变量类型的时候,就需要用到这些基本的类型了,这些类型都是常量,从1-14。 26 | 27 | ## 复杂类型的映射 28 | 针对vector、map、struct三种基本的类型,有一些特殊的打包解包的机制,因此需要引入特别的数据类型: 29 | vector: 30 | ``` 31 | vector => \TARS_VECTOR 32 | 它同时具有两个成员函数pushBack()和push_back() 33 | 入参为取决于vector本身是包含什么类型的数组 34 | 35 | 例如: 36 | $shorts = ["test1","test2"]; 37 | $vector = new \TARS_VECTOR(\TARS::STRING); //定义一个string类型的vector 38 | foreach ($shorts as $short) { 39 | $vector->pushBack($short); //依次吧test1,test2两个元素,压入vector中 40 | } 41 | ``` 42 | map: 43 | ``` 44 | map => \TARS_MAP 45 | 它同时具有两个成员函数pushBack()和push_back() 46 | 入参为取决于map本身包含什么类型 47 | 48 | 例如: 49 | $strings = [["test1"=>1],["test2"=>2]]; 50 | $map = new \TARS_MAP(\TARS::STRING,\TARS::INT64); //定义一个key为string,value是int64的map 51 | foreach ($strings as $string) { 52 | $map->pushBack($string); //依次把两个元素压入map中,注意pushBack接收一个array,且array只有一个元素 53 | } 54 | ``` 55 | 56 | struct: 57 | ``` 58 | struct => \TARS_Struct 59 | struct的构造函数比较特殊,接收classname和classfields两个参数 60 | 第一个描述名称,第二个描述struct内的变量的信息 61 | 62 | 例如: 63 | class SimpleStruct extends \TARS_Struct { 64 | const ID = 0; //TARS文件中每个struct的tag 65 | const COUNT = 1; 66 | 67 | public $id; //strcut中每个元素的值保存在这里 68 | public $count; 69 | 70 | protected static $fields = array( 71 | self::ID => array( 72 | 'name'=>'id',//struct中每个元素的名称 73 | 'required'=>true,//struct中每个元素是否必须,对应tars文件中的require和optional 74 | 'type'=>\TARS::INT64,//struct中每个元素的类型 75 | ), 76 | self::COUNT => array( 77 | 'name'=>'count', 78 | 'required'=>true, 79 | 'type'=>\TARS::UINT8, 80 | ), 81 | ); 82 | 83 | public function __construct() { 84 | parent::__construct('App_Server_Servant.SimpleStruct', self::$fields); 85 | } 86 | } 87 | 88 | ``` 89 | 90 | ## tars2php使用方法 91 | 如果用户只有使用打包解包需求的,那么使用流程如下: 92 | 93 | 0. 准备一份tars协议文件,例如example.tars 94 | 95 | 1. 编写一个tars.proto.php文件,这是用来生成代码的配置文件。 96 | ``` 97 | //本范例的servant name为PHPTest.PHPServer.obj 98 | return array( 99 | 'appName' => 'PHPTest', //tars服务servant name 的第一部分 100 | 'serverName' => 'PHPServer', //tars服务servant name 的第二部分 101 | 'objName' => 'obj', //tars服务servant name 的第三部分 102 | 'withServant' => true,//决定是服务端,还是客户端的自动生成 103 | 'tarsFiles' => array( 104 | './example.tars' //tars文件的地址 105 | ), 106 | 'dstPath' => './server/', //生成php文件的位置 107 | 'namespacePrefix' => 'Server\servant', //生成php文件的命名空间前缀 108 | ); 109 | ``` 110 | 2. 执行php ./tars2php.php ./tars.proto.php 111 | 112 | 3. 工具会根据servant name自动生成三级目录结构,demo中会在./server目录下生成PHPTest/PHPServer/obj/目录,obj目录下的classers是struct对应的php对象,tars目录是tars协议文件本身 。 113 | 114 | 如example.tars中的struct: 115 | ``` 116 | struct SimpleStruct { 117 | 0 require long id=0; 118 | 1 require unsigned int count=0; 119 | 2 require short page=0; 120 | }; 121 | ``` 122 | 转变成classes/SimpleStruct.php 123 | 124 | ``` 125 | array( 140 | 'name'=>'id', //tars协议中没个元素的name 141 | 'required'=>true, //tars协议中是require或者optional 142 | 'type'=>\TARS::INT64, //类型 143 | ), 144 | self::COUNT => array( 145 | 'name'=>'count', 146 | 'required'=>true, 147 | 'type'=>\TARS::UINT32, 148 | ), 149 | self::PAGE => array( 150 | 'name'=>'page', 151 | 'required'=>true, 152 | 'type'=>\TARS::SHORT, 153 | ), 154 | ); 155 | 156 | public function __construct() { 157 | parent::__construct('PHPTest_PHPServer_obj_SimpleStruct', self::$_fields); 158 | } 159 | } 160 | ``` 161 | 162 | 4. 以example.tars中的interface部分会自动生成单独的已interface命名的php文件。 163 | 例如`int testLofofTags(LotofTags tags, out LotofTags outtags);`接口生成的方法如下 164 | 165 | server部分 166 | ``` 167 | _iVersion = $this->_iVersion; 187 | $requestPacket->_funcName = __FUNCTION__; 188 | $requestPacket->_servantName = $this->_servantName; 189 | 190 | $encodeBufs = []; 191 | 192 | $__buffer = TUPAPIWrapper::putStruct("tags",1,$tags,$this->_iVersion); //打包第一个参数tags 193 | $encodeBufs['tags'] = $__buffer; 194 | 195 | $requestPacket->_encodeBufs = $encodeBufs; //在请求包中设置请求bufs 196 | 197 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); //发送请求包,接收返回包 198 | 199 | $ret = TUPAPIWrapper::getStruct("outtags",2,$outtags,$sBuffer,$this->_iVersion); //从返回包中解出第一个输出参数outtags 200 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); //解出返回参数 返回参数 name是空,tag为0 201 | 202 | } 203 | catch (\Exception $e) { 204 | throw $e; 205 | } 206 | ``` 207 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Instructions for using tars2php 2 | 3 | 4 | 5 | Brief introduction 6 | 7 | The main function of tars2php is to automatically generate the PHP code of client side and server side through the tars protocol file, which is used by everyone. (the server side is mainly framework code, and the actual business logic needs to be supplemented and implemented by itself) 8 | 9 | 10 | 11 | ## Mapping of basic types 12 | 13 | Here is our mapping of basic types: 14 | ``` 15 | bool => \TARS::BOOL 16 | char => \TARS::CHAR 17 | uint8 => \TARS::UINT8 18 | short => \TARS::SHORT 19 | uint16 => \TARS::UINT16 20 | float => \TARS::FLOAT 21 | double => \TARS::DOUBLE 22 | int32 => \TARS::INT32 23 | uint32 => \TARS::UINT32 24 | int64 => \TARS::INT64 25 | string => \TARS::STRING 26 | vector => \TARS::VECTOR 27 | map => \TARS::MAP 28 | struct => \TARS::STRUCT 29 | ``` 30 | When we need to identify specific variable types, we need to use these basic types, which are constants, from 1-14. 31 | 32 | 33 | 34 | ##Mapping of complex types 35 | 36 | There are some special packaging and unpacking mechanisms for vector, map and struct. Therefore, special data types need to be introduced: 37 | 38 | Vector: 39 | ``` 40 | vector => \TARS_VECTOR 41 | It has two member functions, push back() and push back() 42 | 43 | The input parameter depends on what type of array the vector itself contains 44 | 45 | 46 | 47 | For example: 48 | $shorts = ["test1","test2"]; 49 | $vector = new \TARS_VECTOR(\TARS::STRING); //定义一个string类型的vector 50 | foreach ($shorts as $short) { 51 | $vector->pushBack($short); //依次吧test1,test2两个元素,压入vector中 52 | } 53 | ``` 54 | map: 55 | ``` 56 | map => \TARS_MAP 57 | It has two member functions, push back() and push back() 58 | 59 | The input parameter depends on what type the map itself contains 60 | 61 | 62 | 63 | For example: 64 | $strings = [["test1"=>1],["test2"=>2]]; 65 | $map = new \TARS_MAP(\TARS::STRING,\TARS::INT64); //定义一个key为string,value是int64的map 66 | foreach ($strings as $string) { 67 | $map->pushBack($string); //Press two elements into the map in turn, and notice that pushback receives an array, and that array has only one element 68 | } 69 | ``` 70 | 71 | struct: 72 | ``` 73 | struct => \TARS_Struct 74 | sThe constructor of struct is special. It takes two parameters, classname and classfields 75 | 76 | The first describes the name, and the second describes the information of the variables in struct 77 | 78 | 79 | 80 | For example: 81 | class SimpleStruct extends \TARS_Struct { 82 | const ID = 0; //TARS file every struct的tag 83 | const COUNT = 1; 84 | 85 | public $id; //strcutThe values of each element in are saved here 86 | public $count; 87 | 88 | protected static $fields = array( 89 | self::ID => array( 90 | 'name'=>'id',//struct every element 91 | 'required'=>true,//Whether each element in struct is required or not corresponds to the requirements and optional in the tars file 92 | 'type'=>\TARS::INT64,//struct every element type 93 | ), 94 | self::COUNT => array( 95 | 'name'=>'count', 96 | 'required'=>true, 97 | 'type'=>\TARS::UINT8, 98 | ), 99 | ); 100 | 101 | public function __construct() { 102 | parent::__construct('App_Server_Servant.SimpleStruct', self::$fields); 103 | } 104 | } 105 | ``` 106 | 107 | ## How to use tars2php 108 | 109 | If the user only uses packaging and unpacking requirements, the process is as follows: 110 | 111 | 112 | 113 | 0. Prepare a tar protocol file, such as example.tar 114 | 115 | 116 | 117 | 1. Write a tar.proto.php file, which is the configuration file used to generate code. 118 | 119 | ``` 120 | 121 | //The service name of this example is phptest.phpserver.obj 122 | return array( 123 | ‘appName’=>‘PHPTest’,//tars name 124 | 125 | “server name”=>“PHPServer”,//tars servant name 126 | 127 | ‘obj name’=>‘obj’,//tars slaver name 128 | 129 | “with servant”=>correct,// 130 | 131 | 'tarsFiles'=>array( 132 | 133 | './example.tars'//tars 134 | 135 | ), 136 | 137 | 'dstPath'=>'./server/',//php 138 | 139 | 'namespace prefix' = > 'server / service',//php' 140 | 141 | ); 142 | ``` 143 | 2. exec php ./tars2php.php ./tars.proto.php 144 | 145 | 3. The tool will automatically generate three-level directory structure according to the service name. In the demo, the phptest / PHP server / obj / directory will be generated under the. / server directory. The classes under the obj directory are the PHP objects corresponding to struct, and the tar directory is the tar protocol file itself. 146 | 147 | For example, struct in example.tar: 148 | ``` 149 | struct SimpleStruct { 150 | 0 require long id=0; 151 | 1 require unsigned int count=0; 152 | 2 require short page=0; 153 | }; 154 | ``` 155 | 转变成classes/SimpleStruct.php 156 | 157 | ``` 158 | array( 173 | 'name'=>'id', //tars Name of no element in the agreement 174 | 'required'=>true, //tars Required or optional in the agreement 175 | 'type'=>\TARS::INT64, //type 176 | ), 177 | self::COUNT => array( 178 | 'name'=>'count', 179 | 'required'=>true, 180 | 'type'=>\TARS::UINT32, 181 | ), 182 | self::PAGE => array( 183 | 'name'=>'page', 184 | 'required'=>true, 185 | 'type'=>\TARS::SHORT, 186 | ), 187 | ); 188 | 189 | public function __construct() { 190 | parent::__construct('PHPTest_PHPServer_obj_SimpleStruct', self::$_fields); 191 | } 192 | } 193 | ``` 194 | 195 | 4. The interface section in example. Tar automatically generates a separate interface named PHP file. 196 | 197 | For example, 'int testlofoftags (lotoftags tags, out lotoftags outbound);' the interface generation method is as follows 198 | 199 | 200 | 201 | Part server 202 | 203 | ``` 204 | 205 | _iVersion = $this->_iVersion; 231 | $requestPacket->_funcName = __FUNCTION__; 232 | $requestPacket->_servantName = $this->_servantName; 233 | 234 | $encodeBufs = []; 235 | 236 | $__buffer = TUPAPIWrapper::putStruct("tags",1,$tags,$this->_iVersion); //Package first parameter tags 237 | $encodeBufs['tags'] = $__buffer; 238 | 239 | $requestPacket->_encodeBufs = $encodeBufs; //Set request in request package bufs 240 | 241 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); //Send request package, receive return package 242 | 243 | $ret = TUPAPIWrapper::getStruct("outtags",2,$outtags,$sBuffer,$this->_iVersion); //Extract the first output parameter from the return packageouttags 244 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); //The return parameter name is empty and the tag is 0 245 | 246 | } 247 | catch (\Exception $e) { 248 | throw $e; 249 | } 250 | ``` -------------------------------------------------------------------------------- /tests/client/PHPTest/PHPServer/obj/TestTafServiceServant.php: -------------------------------------------------------------------------------- 1 | setServantName($this->_servantName); 25 | $this->_communicator = new Communicator($config); 26 | $this->_iVersion = $config->getIVersion(); 27 | $this->_iTimeout = empty($config->getAsyncInvokeTimeout())?2:$config->getAsyncInvokeTimeout(); 28 | } catch (\Exception $e) { 29 | throw $e; 30 | } 31 | } 32 | 33 | public function testTafServer() { 34 | try { 35 | $requestPacket = new RequestPacket(); 36 | $requestPacket->_iVersion = $this->_iVersion; 37 | $requestPacket->_funcName = __FUNCTION__; 38 | $requestPacket->_servantName = $this->_servantName; 39 | $requestPacket->_contexts = $this->_contexts; 40 | $requestPacket->_statuses = $this->_statuses; 41 | $encodeBufs = []; 42 | 43 | $requestPacket->_encodeBufs = $encodeBufs; 44 | 45 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 46 | 47 | } 48 | catch (\Exception $e) { 49 | throw $e; 50 | } 51 | } 52 | 53 | public function testLofofTags(LotofTags $tags,LotofTags &$outtags) { 54 | try { 55 | $requestPacket = new RequestPacket(); 56 | $requestPacket->_iVersion = $this->_iVersion; 57 | $requestPacket->_funcName = __FUNCTION__; 58 | $requestPacket->_servantName = $this->_servantName; 59 | $requestPacket->_contexts = $this->_contexts; 60 | $requestPacket->_statuses = $this->_statuses; 61 | $encodeBufs = []; 62 | 63 | $__buffer = TUPAPIWrapper::putStruct("tags",1,$tags,$this->_iVersion); 64 | $encodeBufs['tags'] = $__buffer; 65 | $requestPacket->_encodeBufs = $encodeBufs; 66 | 67 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 68 | 69 | $ret = TUPAPIWrapper::getStruct("outtags",2,$outtags,$sBuffer,$this->_iVersion); 70 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); 71 | 72 | } 73 | catch (\Exception $e) { 74 | throw $e; 75 | } 76 | } 77 | 78 | public function sayHelloWorld($name,&$outGreetings) { 79 | try { 80 | $requestPacket = new RequestPacket(); 81 | $requestPacket->_iVersion = $this->_iVersion; 82 | $requestPacket->_funcName = __FUNCTION__; 83 | $requestPacket->_servantName = $this->_servantName; 84 | $requestPacket->_contexts = $this->_contexts; 85 | $requestPacket->_statuses = $this->_statuses; 86 | $encodeBufs = []; 87 | 88 | $__buffer = TUPAPIWrapper::putString("name",1,$name,$this->_iVersion); 89 | $encodeBufs['name'] = $__buffer; 90 | $requestPacket->_encodeBufs = $encodeBufs; 91 | 92 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 93 | 94 | $outGreetings = TUPAPIWrapper::getString("outGreetings",2,$sBuffer,$this->_iVersion); 95 | } 96 | catch (\Exception $e) { 97 | throw $e; 98 | } 99 | } 100 | 101 | public function testBasic($a,$b,$c,&$d,&$e,&$f) { 102 | try { 103 | $requestPacket = new RequestPacket(); 104 | $requestPacket->_iVersion = $this->_iVersion; 105 | $requestPacket->_funcName = __FUNCTION__; 106 | $requestPacket->_servantName = $this->_servantName; 107 | $requestPacket->_contexts = $this->_contexts; 108 | $requestPacket->_statuses = $this->_statuses; 109 | $encodeBufs = []; 110 | 111 | $__buffer = TUPAPIWrapper::putBool("a",1,$a,$this->_iVersion); 112 | $encodeBufs['a'] = $__buffer; 113 | $__buffer = TUPAPIWrapper::putInt32("b",2,$b,$this->_iVersion); 114 | $encodeBufs['b'] = $__buffer; 115 | $__buffer = TUPAPIWrapper::putString("c",3,$c,$this->_iVersion); 116 | $encodeBufs['c'] = $__buffer; 117 | $requestPacket->_encodeBufs = $encodeBufs; 118 | 119 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 120 | 121 | $d = TUPAPIWrapper::getBool("d",4,$sBuffer,$this->_iVersion); 122 | $e = TUPAPIWrapper::getInt32("e",5,$sBuffer,$this->_iVersion); 123 | $f = TUPAPIWrapper::getString("f",6,$sBuffer,$this->_iVersion); 124 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); 125 | 126 | } 127 | catch (\Exception $e) { 128 | throw $e; 129 | } 130 | } 131 | 132 | public function testStruct($a,SimpleStruct $b,OutStruct &$d) { 133 | try { 134 | $requestPacket = new RequestPacket(); 135 | $requestPacket->_iVersion = $this->_iVersion; 136 | $requestPacket->_funcName = __FUNCTION__; 137 | $requestPacket->_servantName = $this->_servantName; 138 | $requestPacket->_contexts = $this->_contexts; 139 | $requestPacket->_statuses = $this->_statuses; 140 | $encodeBufs = []; 141 | 142 | $__buffer = TUPAPIWrapper::putInt64("a",1,$a,$this->_iVersion); 143 | $encodeBufs['a'] = $__buffer; 144 | $__buffer = TUPAPIWrapper::putStruct("b",2,$b,$this->_iVersion); 145 | $encodeBufs['b'] = $__buffer; 146 | $requestPacket->_encodeBufs = $encodeBufs; 147 | 148 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 149 | 150 | $ret = TUPAPIWrapper::getStruct("d",3,$d,$sBuffer,$this->_iVersion); 151 | return TUPAPIWrapper::getString("",0,$sBuffer,$this->_iVersion); 152 | 153 | } 154 | catch (\Exception $e) { 155 | throw $e; 156 | } 157 | } 158 | 159 | public function testMap($a,SimpleStruct $b,$m1,OutStruct &$d,&$m2) { 160 | try { 161 | $requestPacket = new RequestPacket(); 162 | $requestPacket->_iVersion = $this->_iVersion; 163 | $requestPacket->_funcName = __FUNCTION__; 164 | $requestPacket->_servantName = $this->_servantName; 165 | $requestPacket->_contexts = $this->_contexts; 166 | $requestPacket->_statuses = $this->_statuses; 167 | $encodeBufs = []; 168 | 169 | $__buffer = TUPAPIWrapper::putShort("a",1,$a,$this->_iVersion); 170 | $encodeBufs['a'] = $__buffer; 171 | $__buffer = TUPAPIWrapper::putStruct("b",2,$b,$this->_iVersion); 172 | $encodeBufs['b'] = $__buffer; 173 | $m1_map = new \TARS_Map(\TARS::STRING,\TARS::STRING); 174 | foreach($m1 as $key => $value) { 175 | $m1_map->pushBack([$key => $value]); 176 | } 177 | $__buffer = TUPAPIWrapper::putMap("m1",3,$m1_map,$this->_iVersion); 178 | $encodeBufs['m1'] = $__buffer; 179 | $requestPacket->_encodeBufs = $encodeBufs; 180 | 181 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 182 | 183 | $ret = TUPAPIWrapper::getStruct("d",4,$d,$sBuffer,$this->_iVersion); 184 | $m2 = TUPAPIWrapper::getMap("m2",5,new \TARS_Map(\TARS::INT32,new SimpleStruct()),$sBuffer,$this->_iVersion); 185 | return TUPAPIWrapper::getString("",0,$sBuffer,$this->_iVersion); 186 | 187 | } 188 | catch (\Exception $e) { 189 | throw $e; 190 | } 191 | } 192 | 193 | public function testVector($a,$v1,$v2,&$v3,&$v4) { 194 | try { 195 | $requestPacket = new RequestPacket(); 196 | $requestPacket->_iVersion = $this->_iVersion; 197 | $requestPacket->_funcName = __FUNCTION__; 198 | $requestPacket->_servantName = $this->_servantName; 199 | $requestPacket->_contexts = $this->_contexts; 200 | $requestPacket->_statuses = $this->_statuses; 201 | $encodeBufs = []; 202 | 203 | $__buffer = TUPAPIWrapper::putInt32("a",1,$a,$this->_iVersion); 204 | $encodeBufs['a'] = $__buffer; 205 | $v1_vec = new \TARS_Vector(\TARS::STRING); 206 | foreach($v1 as $singlev1) { 207 | $v1_vec->pushBack($singlev1); 208 | } 209 | $__buffer = TUPAPIWrapper::putVector("v1",2,$v1_vec,$this->_iVersion); 210 | $encodeBufs['v1'] = $__buffer; 211 | $v2_vec = new \TARS_Vector(new SimpleStruct()); 212 | foreach($v2 as $singlev2) { 213 | $v2_vec->pushBack($singlev2); 214 | } 215 | $__buffer = TUPAPIWrapper::putVector("v2",3,$v2_vec,$this->_iVersion); 216 | $encodeBufs['v2'] = $__buffer; 217 | $requestPacket->_encodeBufs = $encodeBufs; 218 | 219 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 220 | 221 | $v3 = TUPAPIWrapper::getVector("v3",4,new \TARS_Vector(\TARS::INT32),$sBuffer,$this->_iVersion); 222 | $v4 = TUPAPIWrapper::getVector("v4",5,new \TARS_Vector(new OutStruct()),$sBuffer,$this->_iVersion); 223 | return TUPAPIWrapper::getString("",0,$sBuffer,$this->_iVersion); 224 | 225 | } 226 | catch (\Exception $e) { 227 | throw $e; 228 | } 229 | } 230 | 231 | public function testReturn() { 232 | try { 233 | $requestPacket = new RequestPacket(); 234 | $requestPacket->_iVersion = $this->_iVersion; 235 | $requestPacket->_funcName = __FUNCTION__; 236 | $requestPacket->_servantName = $this->_servantName; 237 | $requestPacket->_contexts = $this->_contexts; 238 | $requestPacket->_statuses = $this->_statuses; 239 | $encodeBufs = []; 240 | 241 | $requestPacket->_encodeBufs = $encodeBufs; 242 | 243 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 244 | 245 | $returnVal = new SimpleStruct(); 246 | TUPAPIWrapper::getStruct("",0,$returnVal,$sBuffer,$this->_iVersion); 247 | return $returnVal; 248 | 249 | } 250 | catch (\Exception $e) { 251 | throw $e; 252 | } 253 | } 254 | 255 | public function testReturn2() { 256 | try { 257 | $requestPacket = new RequestPacket(); 258 | $requestPacket->_iVersion = $this->_iVersion; 259 | $requestPacket->_funcName = __FUNCTION__; 260 | $requestPacket->_servantName = $this->_servantName; 261 | $requestPacket->_contexts = $this->_contexts; 262 | $requestPacket->_statuses = $this->_statuses; 263 | $encodeBufs = []; 264 | 265 | $requestPacket->_encodeBufs = $encodeBufs; 266 | 267 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 268 | 269 | return TUPAPIWrapper::getMap("",0,new \TARS_Map(\TARS::STRING,\TARS::STRING),$sBuffer,$this->_iVersion); 270 | 271 | } 272 | catch (\Exception $e) { 273 | throw $e; 274 | } 275 | } 276 | 277 | public function testComplicatedStruct(ComplicatedStruct $cs,$vcs,ComplicatedStruct &$ocs,&$ovcs) { 278 | try { 279 | $requestPacket = new RequestPacket(); 280 | $requestPacket->_iVersion = $this->_iVersion; 281 | $requestPacket->_funcName = __FUNCTION__; 282 | $requestPacket->_servantName = $this->_servantName; 283 | $requestPacket->_contexts = $this->_contexts; 284 | $requestPacket->_statuses = $this->_statuses; 285 | $encodeBufs = []; 286 | 287 | $__buffer = TUPAPIWrapper::putStruct("cs",1,$cs,$this->_iVersion); 288 | $encodeBufs['cs'] = $__buffer; 289 | $vcs_vec = new \TARS_Vector(new ComplicatedStruct()); 290 | foreach($vcs as $singlevcs) { 291 | $vcs_vec->pushBack($singlevcs); 292 | } 293 | $__buffer = TUPAPIWrapper::putVector("vcs",2,$vcs_vec,$this->_iVersion); 294 | $encodeBufs['vcs'] = $__buffer; 295 | $requestPacket->_encodeBufs = $encodeBufs; 296 | 297 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 298 | 299 | $ret = TUPAPIWrapper::getStruct("ocs",3,$ocs,$sBuffer,$this->_iVersion); 300 | $ovcs = TUPAPIWrapper::getVector("ovcs",4,new \TARS_Vector(new ComplicatedStruct()),$sBuffer,$this->_iVersion); 301 | return TUPAPIWrapper::getVector("",0,new \TARS_Vector(new SimpleStruct()),$sBuffer,$this->_iVersion); 302 | 303 | } 304 | catch (\Exception $e) { 305 | throw $e; 306 | } 307 | } 308 | 309 | public function testComplicatedMap($mcs,&$omcs) { 310 | try { 311 | $requestPacket = new RequestPacket(); 312 | $requestPacket->_iVersion = $this->_iVersion; 313 | $requestPacket->_funcName = __FUNCTION__; 314 | $requestPacket->_servantName = $this->_servantName; 315 | $requestPacket->_contexts = $this->_contexts; 316 | $requestPacket->_statuses = $this->_statuses; 317 | $encodeBufs = []; 318 | 319 | $mcs_map = new \TARS_Map(\TARS::STRING,new ComplicatedStruct()); 320 | foreach($mcs as $key => $value) { 321 | $mcs_map->pushBack([$key => $value]); 322 | } 323 | $__buffer = TUPAPIWrapper::putMap("mcs",1,$mcs_map,$this->_iVersion); 324 | $encodeBufs['mcs'] = $__buffer; 325 | $requestPacket->_encodeBufs = $encodeBufs; 326 | 327 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 328 | 329 | $omcs = TUPAPIWrapper::getMap("omcs",2,new \TARS_Map(\TARS::STRING,new ComplicatedStruct()),$sBuffer,$this->_iVersion); 330 | return TUPAPIWrapper::getMap("",0,new \TARS_Map(\TARS::STRING,new ComplicatedStruct()),$sBuffer,$this->_iVersion); 331 | 332 | } 333 | catch (\Exception $e) { 334 | throw $e; 335 | } 336 | } 337 | 338 | public function testEmpty($a,&$b1,&$in2,OutStruct &$d,&$v3,&$v4) { 339 | try { 340 | $requestPacket = new RequestPacket(); 341 | $requestPacket->_iVersion = $this->_iVersion; 342 | $requestPacket->_funcName = __FUNCTION__; 343 | $requestPacket->_servantName = $this->_servantName; 344 | $requestPacket->_contexts = $this->_contexts; 345 | $requestPacket->_statuses = $this->_statuses; 346 | $encodeBufs = []; 347 | 348 | $__buffer = TUPAPIWrapper::putShort("a",1,$a,$this->_iVersion); 349 | $encodeBufs['a'] = $__buffer; 350 | $requestPacket->_encodeBufs = $encodeBufs; 351 | 352 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 353 | 354 | $b1 = TUPAPIWrapper::getBool("b1",2,$sBuffer,$this->_iVersion); 355 | $in2 = TUPAPIWrapper::getInt32("in2",3,$sBuffer,$this->_iVersion); 356 | $ret = TUPAPIWrapper::getStruct("d",4,$d,$sBuffer,$this->_iVersion); 357 | $v3 = TUPAPIWrapper::getVector("v3",5,new \TARS_Vector(new OutStruct()),$sBuffer,$this->_iVersion); 358 | $v4 = TUPAPIWrapper::getVector("v4",6,new \TARS_Vector(\TARS::INT32),$sBuffer,$this->_iVersion); 359 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); 360 | 361 | } 362 | catch (\Exception $e) { 363 | throw $e; 364 | } 365 | } 366 | 367 | public function testSelf() { 368 | try { 369 | $requestPacket = new RequestPacket(); 370 | $requestPacket->_iVersion = $this->_iVersion; 371 | $requestPacket->_funcName = __FUNCTION__; 372 | $requestPacket->_servantName = $this->_servantName; 373 | $requestPacket->_contexts = $this->_contexts; 374 | $requestPacket->_statuses = $this->_statuses; 375 | $encodeBufs = []; 376 | 377 | $requestPacket->_encodeBufs = $encodeBufs; 378 | 379 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 380 | 381 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); 382 | 383 | } 384 | catch (\Exception $e) { 385 | throw $e; 386 | } 387 | } 388 | 389 | public function testProperty() { 390 | try { 391 | $requestPacket = new RequestPacket(); 392 | $requestPacket->_iVersion = $this->_iVersion; 393 | $requestPacket->_funcName = __FUNCTION__; 394 | $requestPacket->_servantName = $this->_servantName; 395 | $requestPacket->_contexts = $this->_contexts; 396 | $requestPacket->_statuses = $this->_statuses; 397 | $encodeBufs = []; 398 | 399 | $requestPacket->_encodeBufs = $encodeBufs; 400 | 401 | $sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout); 402 | 403 | return TUPAPIWrapper::getInt32("",0,$sBuffer,$this->_iVersion); 404 | 405 | } 406 | catch (\Exception $e) { 407 | throw $e; 408 | } 409 | } 410 | 411 | } 412 | 413 | -------------------------------------------------------------------------------- /src/proto2php.php: -------------------------------------------------------------------------------- 1 | moduleScan(); 14 | 15 | $fileConverter->moduleParse(); 16 | 17 | class Utils 18 | { 19 | public static function inIdentifier($char) 20 | { 21 | return ($char >= 'a' & $char <= 'z') | 22 | ($char >= 'A' & $char <= 'Z') | 23 | ($char >= '0' & $char <= '9') | 24 | ($char == '_'); 25 | } 26 | 27 | public static function abnormalExit($level, $msg) 28 | { 29 | echo "[$level]$msg"."\n"; 30 | exit; 31 | } 32 | 33 | public static function pregMatchByName($name, $line) 34 | { 35 | // 处理第一行,正则匹配出classname 36 | $Tokens = preg_split("/$name/", $line); 37 | 38 | $mathName = $Tokens[1]; 39 | $mathName = trim($mathName, " \r\0\x0B\t\n{"); 40 | 41 | preg_match('/[a-zA-Z][0-9a-zA-Z]/', $mathName, $matches); 42 | if (empty($matches)) { 43 | //Utils::abnormalExit('error',$name.'名称有误'.$line); 44 | } 45 | 46 | return $mathName; 47 | } 48 | 49 | public static function isReturn($char) 50 | { 51 | if ($char == "\n" || $char == '\r' || bin2hex($char) == '0a' || bin2hex($char) == '0b' || 52 | bin2hex($char) == '0c' || bin2hex($char) == '0d') { 53 | return true; 54 | } else { 55 | return false; 56 | } 57 | } 58 | } 59 | 60 | class FileConverter 61 | { 62 | public $moduleName; 63 | public $uniqueName; 64 | public $interfaceName; 65 | public $fromFile; 66 | public $outputDir; 67 | 68 | public $appName; 69 | public $serverName; 70 | public $objName; 71 | public $servantName; 72 | 73 | public $namespaceName; 74 | public $namespacePrefix; 75 | 76 | public $preStructs = []; 77 | public $preEnums = []; 78 | public $preConsts = []; 79 | public $preNamespaceStructs = []; 80 | public $preNamespaceEnums = []; 81 | 82 | public $package; 83 | 84 | public function __construct($config) 85 | { 86 | $this->fromFile = $config['tarsFiles'][0]; 87 | if (empty($config['appName']) || empty($config['serverName']) || empty($config['objName'])) { 88 | Utils::abnormalExit('error', 'appName or serverName or objName empty!'); 89 | } 90 | $this->servantName = $config['appName'].'.'.$config['serverName'].'.'.$config['objName']; 91 | 92 | $this->appName = $config['appName']; 93 | $this->serverName = $config['serverName']; 94 | $this->objName = $config['objName']; 95 | 96 | $this->outputDir = empty($config['dstPath']) ? './' : $config['dstPath'].'/'; 97 | $this->outputProtocDir = empty($config['protocDstPath']) ? './' : $config['protocDstPath'].'/'; 98 | 99 | $pos = strrpos($this->fromFile, '/', -1); 100 | $inputDir = substr($this->fromFile, 0, $pos); 101 | $this->inputDir = $inputDir; 102 | 103 | $this->namespacePrefix = $config['namespacePrefix']; 104 | $this->withServant = $config['withServant']; 105 | 106 | $this->initDir(); 107 | 108 | $this->checkProtoc(); 109 | $this->runProtoc(); 110 | } 111 | 112 | /** 113 | * 首先需要初始化一些文件目录. 114 | * 115 | * @return [type] [description] 116 | */ 117 | public function initDir() 118 | { 119 | if (strtolower(substr(php_uname('a'), 0, 3)) === 'win') { 120 | $this->outputDir = str_replace('/', '\\', $this->outputDir); 121 | $this->fromFile = str_replace('/', '\\', $this->fromFile); 122 | 123 | $this->moduleName = $this->appName.'\\'.$this->serverName; 124 | exec('if exist ' . $this->outputDir . $this->moduleName . ' rd /s /q ' . $this->outputDir . $this->moduleName); 125 | 126 | exec('mkdir '.$this->outputDir.$this->moduleName.'\\tars'); 127 | exec('copy '.$this->fromFile.' '.$this->outputDir.$this->moduleName.'\\tars'); 128 | } else { 129 | $this->moduleName = $this->appName.'/'.$this->serverName; 130 | exec('rm -rf '.$this->outputDir.$this->moduleName); 131 | 132 | exec('mkdir -p '.$this->outputDir.$this->moduleName.'/tars'); 133 | exec('cp '.$this->fromFile.' '.$this->outputDir.$this->moduleName.'/tars'); 134 | } 135 | 136 | $this->namespaceName = empty($this->namespacePrefix) ? $this->appName.'\\'.$this->serverName 137 | : $this->namespacePrefix.'\\'.$this->appName.'\\'.$this->serverName; 138 | 139 | $this->uniqueName = $this->appName.'_'.$this->serverName; 140 | } 141 | 142 | public function usage() 143 | { 144 | echo 'php proto2php.php tars.proto.php'; 145 | } 146 | 147 | public function moduleParse() 148 | { 149 | $fp = fopen($this->fromFile, 'r'); 150 | if (!$fp) { 151 | $this->usage(); 152 | exit; 153 | } 154 | 155 | $this->package = ''; 156 | while (($line = fgets($fp, 1024)) !== false) { 157 | $packageFlag = strpos(strtolower($line), 'package'); 158 | if ($packageFlag !== false) { 159 | $this->package = Utils::pregMatchByName('package', $line); 160 | $this->package = str_replace(';', '', $this->package); 161 | } 162 | 163 | // 正则匹配,发现是在service中 164 | $serviceFlag = strpos(strtolower($line), 'service'); 165 | if ($serviceFlag !== false) { 166 | $name = Utils::pregMatchByName('service', $line); 167 | $interfaceName = $name.'Servant'; 168 | 169 | $basePath = '/' . $this->package . '.' . $name . '/'; 170 | 171 | // 需要区分一下生成server还是client的代码 172 | if ($this->withServant) { 173 | 174 | $servantParser = new ServantParser($fp, $line, $this->namespaceName, $this->moduleName, 175 | $interfaceName, $this->preStructs, 176 | $this->preEnums, $this->servantName, $this->preNamespaceEnums, $this->preNamespaceStructs, ucfirst(str_replace('.', '\\', $this->package))); 177 | 178 | $servant = $servantParser->parse(); 179 | file_put_contents($this->outputDir.$this->moduleName.'/'.$interfaceName.'.php', $servant); 180 | } else { 181 | 182 | $interfaceParser = new InterfaceParser($fp, $line, $this->namespaceName, $this->moduleName, 183 | $interfaceName, $this->preStructs, 184 | $this->preEnums, $this->servantName, $this->preNamespaceEnums, $this->preNamespaceStructs, $basePath, ucfirst(str_replace('.', '\\', $this->package))); 185 | $interfaces = $interfaceParser->parse(); 186 | 187 | // 需要区分同步和异步的两种方式 188 | file_put_contents($this->outputDir.$this->moduleName.'/'.$interfaceName.'.php', $interfaces['syn']); 189 | } 190 | } 191 | } 192 | } 193 | 194 | public function checkProtoc() 195 | { 196 | $ret = exec("protoc --version", $ret2); 197 | if (empty($ret)) { 198 | echo "you have not install protoc, please check. doc : "; 199 | exit; 200 | } 201 | } 202 | 203 | public function runProtoc() 204 | { 205 | // $exec = "protoc --plugin=protoc-gen-grpc=/usr/local/bin/grpc_php_plugin --php_out={$this->outputDir} {$this->fromFile}"; 206 | $exec = "protoc --php_out={$this->outputProtocDir} {$this->fromFile}"; 207 | $ret = exec($exec); 208 | } 209 | } 210 | 211 | class InterfaceParser 212 | { 213 | public $namespaceName; 214 | public $moduleName; 215 | public $interfaceName; 216 | public $asInterfaceName; 217 | 218 | public $state; 219 | 220 | // 这个结构体,可能会引用的部分,包括其他的结构体、枚举类型、常量 221 | public $useStructs = []; 222 | public $extraUse; 223 | public $preStructs; 224 | public $preEnums; 225 | 226 | public $preNamespaceStructs; 227 | public $preNamespaceEnums; 228 | 229 | public $returnSymbol = "\n"; 230 | public $doubleReturn = "\n\n"; 231 | public $tabSymbol = "\t"; 232 | public $doubleTab = "\t\t"; 233 | public $tripleTab = "\t\t\t"; 234 | public $quardupleTab = "\t\t\t\t"; 235 | 236 | public $extraContructs = ''; 237 | public $extraExtInit = ''; 238 | 239 | public $consts = ''; 240 | public $variables = ''; 241 | public $fields = ''; 242 | 243 | public $funcSet = ''; 244 | 245 | public $servantName; 246 | 247 | public $basePath = ''; 248 | 249 | public function __construct($fp, $line, $namespaceName, $moduleName, 250 | $interfaceName, $preStructs, 251 | $preEnums, $servantName, $preNamespaceEnums, $preNamespaceStructs, $basePath, $paramNamespace) 252 | { 253 | $this->fp = $fp; 254 | $this->namespaceName = $namespaceName; 255 | $this->moduleName = $moduleName; 256 | $this->preStructs = $preStructs; 257 | $this->preEnums = $preEnums; 258 | $this->interfaceName = $interfaceName; 259 | $this->servantName = $servantName; 260 | 261 | $this->extraUse = ''; 262 | $this->useStructs = []; 263 | 264 | $this->preNamespaceEnums = $preNamespaceEnums; 265 | $this->preNamespaceStructs = $preNamespaceStructs; 266 | $this->basePath = $basePath; 267 | 268 | $this->paramNamespace = $paramNamespace; 269 | } 270 | 271 | public function copyAnnotation() 272 | { 273 | // 再读入一个字符 274 | $nextChar = fgetc($this->fp); 275 | // 第一种 276 | if ($nextChar == '/') { 277 | while (1) { 278 | $tmpChar = fgetc($this->fp); 279 | 280 | if ($tmpChar == "\n") { 281 | $this->state = 'lineEnd'; 282 | break; 283 | } 284 | } 285 | 286 | return; 287 | } elseif ($nextChar == '*') { 288 | while (1) { 289 | $tmpChar = fgetc($this->fp); 290 | 291 | if ($tmpChar === false) { 292 | Utils::abnormalExit('error', '注释换行错误,请检查'.$tmpChar); 293 | } elseif ($tmpChar === "\n") { 294 | } elseif (($tmpChar) === '*') { 295 | $nextnextChar = fgetc($this->fp); 296 | if ($nextnextChar == '/') { 297 | return; 298 | } else { 299 | $pos = ftell($this->fp); 300 | fseek($this->fp, $pos - 1); 301 | } 302 | } 303 | } 304 | } 305 | // 注释不正常 306 | else { 307 | Utils::abnormalExit('error', '注释换行错误,请检查'.$nextChar); 308 | } 309 | } 310 | 311 | public function getFileHeader($prefix = '') 312 | { 313 | return "namespaceName.$prefix.';'.$this->doubleReturn. 314 | 'use Tars\\client\\CommunicatorConfig;'.$this->returnSymbol. 315 | 'use Tars\\client\\Communicator;'.$this->returnSymbol. 316 | 'use Tars\\client\\grpc\\GrpcRequestPacket;'.$this->returnSymbol. 317 | 'use Tars\\client\\grpc\\GrpcResponsePacket;'.$this->returnSymbol; 318 | } 319 | 320 | public function getInterfaceBasic() 321 | { 322 | return $this->tabSymbol.'protected $_communicator;'.$this->returnSymbol. 323 | $this->tabSymbol.'protected $_iTimeout;'.$this->returnSymbol. 324 | $this->tabSymbol."public \$_servantName = \"$this->servantName\";".$this->returnSymbol. 325 | $this->tabSymbol."public \$_basePath = \"$this->basePath\";".$this->doubleReturn. 326 | $this->tabSymbol.'public function __construct(CommunicatorConfig $config) {'.$this->returnSymbol. 327 | 328 | $this->doubleTab.'try {'.$this->returnSymbol. 329 | $this->tripleTab.'$config->setServantName($this->_servantName);'.$this->returnSymbol. 330 | $this->tripleTab.'$this->_communicator = new Communicator($config);'.$this->returnSymbol. 331 | $this->tripleTab.'$this->_iTimeout = empty($config->getAsyncInvokeTimeout())?2:$config->getAsyncInvokeTimeout();'.$this->returnSymbol. 332 | $this->doubleTab.'} catch (\\Exception $e) {'.$this->returnSymbol. 333 | $this->tripleTab.'throw $e;'.$this->returnSymbol. 334 | $this->doubleTab.'}'.$this->returnSymbol. 335 | $this->tabSymbol.'}'.$this->doubleReturn; 336 | } 337 | 338 | public function parse() 339 | { 340 | while ($this->state != 'end') { 341 | $this->state = 'init'; 342 | $this->InterfaceFuncParseLine(); 343 | } 344 | 345 | $interfaceClass = $this->getFileHeader('').$this->extraUse.'class '.$this->interfaceName.$this->returnSymbol . '{'.$this->returnSymbol; 346 | 347 | $interfaceClass .= $this->getInterfaceBasic(); 348 | 349 | $interfaceClass .= $this->funcSet; 350 | 351 | $interfaceClass .= '}'.$this->doubleReturn; 352 | 353 | return [ 354 | 'syn' => $interfaceClass, 355 | ]; 356 | } 357 | 358 | /** 359 | * @param $fp 360 | * @param $line 361 | * 这里必须要引入状态机了 362 | */ 363 | public function InterfaceFuncParseLine() 364 | { 365 | $line = ''; 366 | $this->state = 'init'; 367 | while (1) { 368 | $char = fgetc($this->fp); 369 | 370 | if ($this->state == 'init') { 371 | // 有可能是换行 372 | if ($char == '{' || Utils::isReturn($char)) { 373 | continue; 374 | } 375 | // 遇到了注释会用贪婪算法全部处理完,同时填充到struct的类里面去 376 | elseif ($char == '/') { 377 | $this->copyAnnotation(); 378 | break; 379 | } elseif (Utils::inIdentifier($char)) { 380 | $this->state = 'identifier'; 381 | $line .= $char; 382 | } 383 | // 终止条件之1,宣告struct结束 384 | elseif ($char == '}') { 385 | // 需要贪心的读到"\n"为止 386 | while (($lastChar = fgetc($this->fp)) != "\n") { 387 | continue; 388 | } 389 | $this->state = 'end'; 390 | break; 391 | } 392 | } elseif ($this->state == 'identifier') { 393 | if ($char == '/') { 394 | $this->copyAnnotation(); 395 | } elseif ($char == ';') { 396 | $line .= $char; 397 | $this->state = 'lineEnd'; 398 | } elseif (Utils::isReturn($char)) { 399 | continue; 400 | } else { 401 | $line .= $char; 402 | } 403 | } elseif ($this->state == 'lineEnd') { 404 | if ($char == '}') { 405 | // 需要贪心的读到"\n"为止 406 | while (($lastChar = fgetc($this->fp)) != "\n") { 407 | continue; 408 | } 409 | $this->state = 'end'; 410 | } 411 | break; 412 | } elseif ($this->state == 'end') { 413 | break; 414 | } 415 | } 416 | 417 | if (empty($line)) { 418 | return; 419 | } 420 | 421 | $line = trim($line); 422 | 423 | // 如果空行,或者是注释,或者是大括号就直接略过 424 | if (!trim($line) || trim($line)[0] === '/' || trim($line)[0] === '*') { 425 | return; 426 | } 427 | 428 | $ret = preg_match("/rpc +(\w+)\((\w+)\) +returns +\((\w+)\) +{ *};/", $line, $match); 429 | if (!$ret) { 430 | Utils::abnormalExit('error', '匹配正则失败,请检查, 内容:' . $line); 431 | } 432 | 433 | $funcName = $match[1]; 434 | $params[] = $match[2]; 435 | $params[] = $match[3]; 436 | 437 | $this->writeInterfaceLine('void', $funcName, $params); 438 | } 439 | 440 | public function paramParser($params) 441 | { 442 | foreach ($params as $param) { 443 | // 同时要把它增加到本Interface的依赖中 444 | $this->extraUse .= 'use '.$this->paramNamespace.'\\'.$param.';'.$this->returnSymbol; 445 | } 446 | 447 | return [ 448 | 'in' => [ 449 | [ 450 | 'type' => $params[0], 451 | 'wholeType' => '', 452 | 'valueName' => 'inParam', 453 | ] 454 | ], 455 | 'out' => [ 456 | [ 457 | 'type' => $params[1], 458 | 'wholeType' => '', 459 | 'valueName' => 'outParam', 460 | ] 461 | ], 462 | ]; 463 | } 464 | 465 | /** 466 | * @param $tag 467 | * @param $requireType 468 | * @param $type 469 | * @param $name 470 | * @param $wholeType 471 | * @param $defaultValue 472 | */ 473 | public function writeInterfaceLine($returnType, $funcName, $params) 474 | { 475 | $result = $this->paramParser($params); 476 | $inParams = $result['in']; 477 | $outParams = $result['out']; 478 | 479 | // 处理通用的头部 480 | $funcHeader = $this->generateFuncHeader($funcName, $inParams, $outParams); 481 | 482 | $funcBodyArr = $this->generateFuncBody($inParams, $outParams, null); 483 | $synFuncBody = $funcBodyArr['syn']; 484 | 485 | $funcTail = $this->tabSymbol.'}'.$this->doubleReturn; 486 | 487 | $this->funcSet .= $funcHeader.$synFuncBody.$funcTail; 488 | } 489 | 490 | /** 491 | * @param $funcName 492 | * @param $inParams 493 | * @param $outParams 494 | * 495 | * @return string 496 | */ 497 | public function generateFuncHeader($funcName, $inParams, $outParams) 498 | { 499 | $paramsStr = ''; 500 | foreach ($inParams as $param) { 501 | $paramSuffix = '$'.$param['valueName']; 502 | $paramsStr .= $param['type'].' '.$paramSuffix.','; 503 | } 504 | 505 | foreach ($outParams as $param) { 506 | $paramSuffix = '&$'.$param['valueName']; 507 | $paramsStr .= $param['type'].' '.$paramSuffix.','; 508 | } 509 | 510 | $paramsStr = trim($paramsStr, ','); 511 | $paramsStr .= ')' . $this->returnSymbol . ' {' . $this->returnSymbol; 512 | 513 | $funcHeader = $this->tabSymbol.'public function '.$funcName.'('.$paramsStr; 514 | 515 | return $funcHeader; 516 | } 517 | 518 | /** 519 | * @param $funcName 520 | * @param $inParams 521 | * @param $outParams 522 | * 生成函数的包体 523 | */ 524 | public function generateFuncBody($inParams, $outParams) 525 | { 526 | $bodyPrefix = $this->doubleTab.'try {'.$this->returnSymbol; 527 | 528 | $bodySuffix = $this->doubleTab.'catch (\\Exception $e) {'.$this->returnSymbol. 529 | $this->tripleTab.'throw $e;'.$this->returnSymbol. 530 | $this->doubleTab.'}'.$this->returnSymbol; 531 | 532 | $bodyMiddle = $this->tripleTab.'$requestPacket = new GrpcRequestPacket();'.$this->returnSymbol. 533 | $this->tripleTab.'$requestPacket->_funcName = __FUNCTION__;'.$this->returnSymbol. 534 | $this->tripleTab.'$requestPacket->_servantName = $this->_servantName;'.$this->returnSymbol. 535 | $this->tripleTab.'$requestPacket->_basePath = $this->_basePath;'.$this->returnSymbol. 536 | $this->tripleTab.'$requestPacket->_sBuffer = $inParam->serializeToString();'.$this->doubleReturn. 537 | 538 | $this->tripleTab.'$responsePacket = new GrpcResponsePacket();'.$this->returnSymbol. 539 | $this->tripleTab.'$sBuffer = $this->_communicator->invoke($requestPacket, $this->_iTimeout, $responsePacket);'.$this->doubleReturn. 540 | 541 | $this->tripleTab.'$outParam = new '. $outParams[0]['type'] . '();'.$this->returnSymbol. 542 | $this->tripleTab.'$outParam->mergeFromString($sBuffer);'.$this->returnSymbol; 543 | 544 | 545 | $bodyMiddle .= $this->doubleTab.'}'.$this->returnSymbol; 546 | 547 | $bodyStr = $bodyPrefix.$bodyMiddle.$bodySuffix; 548 | 549 | return [ 550 | 'syn' => $bodyStr, 551 | ]; 552 | } 553 | } 554 | 555 | class ServantParser 556 | { 557 | public $namespaceName; 558 | public $moduleName; 559 | public $interfaceName; 560 | 561 | public $state; 562 | 563 | // 这个结构体,可能会引用的部分,包括其他的结构体、枚举类型、常量 564 | public $useStructs = []; 565 | public $extraUse; 566 | public $preStructs; 567 | public $preEnums; 568 | 569 | public $preNamespaceEnums = []; 570 | public $preNamespaceStructs = []; 571 | 572 | public $firstLine; 573 | 574 | public $returnSymbol = "\n"; 575 | public $doubleReturn = "\n\n"; 576 | public $tabSymbol = "\t"; 577 | public $doubleTab = "\t\t"; 578 | public $tripleTab = "\t\t\t"; 579 | public $quardupleTab = "\t\t\t\t"; 580 | 581 | public $extraContructs = ''; 582 | public $extraExtType = ''; 583 | public $extraExtInit = ''; 584 | 585 | public $consts = ''; 586 | public $variables = ''; 587 | public $fields = ''; 588 | 589 | public $funcSet = ''; 590 | 591 | public $servantName; 592 | public $paramNamespace; 593 | 594 | public function __construct($fp, $line, $namespaceName, $moduleName, 595 | $interfaceName, $preStructs, 596 | $preEnums, $servantName, $preNamespaceEnums, $preNamespaceStructs, $paramNamespace) 597 | { 598 | $this->fp = $fp; 599 | $this->firstLine = $line; 600 | $this->namespaceName = $namespaceName; 601 | $this->moduleName = $moduleName; 602 | $this->preStructs = $preStructs; 603 | $this->preEnums = $preEnums; 604 | $this->interfaceName = $interfaceName; 605 | $this->servantName = $servantName; 606 | 607 | $this->extraUse = ''; 608 | $this->useStructs = []; 609 | 610 | $this->preNamespaceEnums = $preNamespaceEnums; 611 | $this->preNamespaceStructs = $preNamespaceStructs; 612 | 613 | $this->paramNamespace = $paramNamespace; 614 | } 615 | 616 | public function getFileHeader($prefix = '') 617 | { 618 | return "namespaceName.$prefix.';'. $this->doubleReturn; 619 | } 620 | 621 | public function parse() 622 | { 623 | while ($this->state != 'end') { 624 | $this->InterfaceFuncParseLine(); 625 | } 626 | 627 | // todo serverName+servant 628 | $interfaceClass = $this->getFileHeader('').$this->extraUse.'interface '.$this->interfaceName.' {'.$this->returnSymbol; 629 | 630 | $interfaceClass .= $this->funcSet; 631 | 632 | $interfaceClass .= '}'.$this->doubleReturn; 633 | 634 | return $interfaceClass; 635 | } 636 | 637 | /** 638 | * @param $startChar 639 | * @param $lineString 640 | * 641 | * @return string 642 | * 专门处理注释 643 | */ 644 | public function copyAnnotation() 645 | { 646 | // 再读入一个字符 647 | $nextChar = fgetc($this->fp); 648 | // 第一种 649 | if ($nextChar == '/') { 650 | while (1) { 651 | $tmpChar = fgetc($this->fp); 652 | if (Utils::isReturn($tmpChar)) { 653 | $this->state = 'lineEnd'; 654 | break; 655 | } 656 | } 657 | 658 | return; 659 | } elseif ($nextChar == '*') { 660 | while (1) { 661 | $tmpChar = fgetc($this->fp); 662 | 663 | if ($tmpChar === false) { 664 | Utils::abnormalExit('error', $this->interfaceName.'注释换行错误,请检查'); 665 | } elseif (Utils::isReturn($tmpChar)) { 666 | } elseif (($tmpChar) === '*') { 667 | $nextnextChar = fgetc($this->fp); 668 | if ($nextnextChar == '/') { 669 | return; 670 | } else { 671 | $pos = ftell($this->fp); 672 | fseek($this->fp, $pos - 1); 673 | } 674 | } 675 | } 676 | } 677 | // 注释不正常 678 | else { 679 | Utils::abnormalExit('error', $this->interfaceName.'注释换行错误,请检查'); 680 | } 681 | } 682 | 683 | /** 684 | * @param $fp 685 | * @param $line 686 | * 这里必须要引入状态机了 687 | * 这里并不一定要一个line呀,应该找)作为结束符 688 | */ 689 | public function InterfaceFuncParseLine() 690 | { 691 | $line = ''; 692 | $this->state = 'init'; 693 | while (1) { 694 | $char = fgetc($this->fp); 695 | 696 | if ($this->state == 'init') { 697 | // 有可能是换行 698 | if ($char == '{' || Utils::isReturn($char)) { 699 | continue; 700 | } 701 | // 遇到了注释会用贪婪算法全部处理完,同时填充到struct的类里面去 702 | elseif ($char == '/') { 703 | $this->copyAnnotation(); 704 | break; 705 | } elseif (Utils::inIdentifier($char)) { 706 | $this->state = 'identifier'; 707 | $line .= $char; 708 | } 709 | // 终止条件之1,宣告struct结束 710 | elseif ($char == '}') { 711 | // 需要贪心的读到"\n"为止 712 | while (($lastChar = fgetc($this->fp)) != "\n") { 713 | continue; 714 | } 715 | $this->state = 'end'; 716 | break; 717 | } 718 | } elseif ($this->state == 'identifier') { 719 | if ($char == '/') { 720 | $this->copyAnnotation(); 721 | } elseif ($char == ';') { 722 | $line .= $char; 723 | $this->state = 'lineEnd'; 724 | } elseif (Utils::isReturn($char)) { 725 | continue; 726 | } else { 727 | $line .= $char; 728 | } 729 | } elseif ($this->state == 'lineEnd') { 730 | if ($char == '}') { 731 | // 需要贪心的读到"\n"为止 732 | while (($lastChar = fgetc($this->fp)) != "\n") { 733 | continue; 734 | } 735 | $this->state = 'end'; 736 | } 737 | break; 738 | } elseif ($this->state == 'end') { 739 | break; 740 | } 741 | } 742 | 743 | if (empty($line)) { 744 | return; 745 | } 746 | 747 | $line = trim($line); 748 | 749 | // 如果空行,或者是注释,或者是大括号就直接略过 750 | if (!trim($line) || trim($line)[0] === '/' || trim($line)[0] === '*') { 751 | return; 752 | } 753 | 754 | $ret = preg_match("/rpc +(\w+) *\((\w+)\) +returns +\((\w+)\) +{ *};?/", $line, $match); 755 | if (!$ret) { 756 | Utils::abnormalExit('error', '匹配正则失败,请检查, 内容:' . $line); 757 | } 758 | 759 | $funcName = $match[1]; 760 | $params[] = $match[2]; 761 | $params[] = $match[3]; 762 | 763 | $this->writeInterfaceLine('void', $funcName, $params); 764 | } 765 | 766 | public function paramParser($params) 767 | { 768 | foreach ($params as $param) { 769 | // 同时要把它增加到本Interface的依赖中 770 | $this->extraUse .= 'use '.$this->paramNamespace.'\\'.$param.';'.$this->returnSymbol; 771 | } 772 | 773 | return [ 774 | 'in' => [ 775 | [ 776 | 'type' => $params[0], 777 | 'wholeType' => '', 778 | 'valueName' => 'inParam', 779 | ] 780 | ], 781 | 'out' => [ 782 | [ 783 | 'type' => $params[1], 784 | 'wholeType' => '', 785 | 'valueName' => 'outParam', 786 | ] 787 | ], 788 | ]; 789 | } 790 | 791 | public function writeInterfaceLine($returnType, $funcName, $params) 792 | { 793 | $result = $this->paramParser($params); 794 | $inParams = $result['in']; 795 | $outParams = $result['out']; 796 | 797 | $funcAnnotation = $this->generateFuncAnnotation($inParams, $outParams, null); 798 | 799 | // 函数定义恰恰是要放在最后面了 800 | $funcDefinition = $this->generateFuncHeader($funcName, $inParams, $outParams); 801 | 802 | $this->funcSet .= $funcAnnotation.$funcDefinition . $this->returnSymbol; 803 | } 804 | 805 | /** 806 | * @param $funcName 807 | * @param $inParams 808 | * @param $outParams 809 | * 810 | * @return string 811 | */ 812 | public function generateFuncHeader($funcName, $inParams, $outParams) 813 | { 814 | $paramsStr = ''; 815 | foreach ($inParams as $param) { 816 | $paramSuffix = '$'.$param['valueName']; 817 | $paramsStr .= $param['type'].' '.$paramSuffix.','; 818 | } 819 | 820 | foreach ($outParams as $param) { 821 | $paramSuffix = '&$'.$param['valueName']; 822 | $paramsStr .= $param['type'].' '.$paramSuffix.','; 823 | } 824 | 825 | $paramsStr = trim($paramsStr, ','); 826 | $paramsStr .= ');'.$this->returnSymbol; 827 | 828 | $funcHeader = $this->tabSymbol.'public function '.$funcName.'('.$paramsStr; 829 | 830 | return $funcHeader; 831 | } 832 | 833 | /** 834 | * @param $funcName 835 | * @param $inParams 836 | * @param $outParams 837 | * 生成函数的包体 838 | */ 839 | public function generateFuncAnnotation($inParams, $outParams, $returnInfo) 840 | { 841 | $bodyPrefix = $this->tabSymbol.'/**'.$this->returnSymbol; 842 | 843 | $bodyMiddle = ''; 844 | 845 | foreach ($inParams as $param) { 846 | 847 | $annotation = $this->tabSymbol.' * @param '; 848 | $type = $param['type']; 849 | $valueName = $param['valueName']; 850 | 851 | $annotation .= '\\' . $this->paramNamespace . '\\' . $type . ' $' . $valueName; 852 | $bodyMiddle .= $annotation.$this->returnSymbol; 853 | } 854 | 855 | foreach ($outParams as $param) { 856 | $annotation = $this->tabSymbol.' * @param '; 857 | $type = $param['type']; 858 | $valueName = $param['valueName']; 859 | 860 | $annotation .= '\\' . $this->paramNamespace . '\\' . $type . ' $' . $valueName; 861 | $annotation .= ' =out='.$this->returnSymbol; 862 | $bodyMiddle .= $annotation; 863 | } 864 | 865 | // 还要尝试去获取一下接口的返回码哦 总是void 866 | $annotation = $this->tabSymbol.' * @return '; 867 | $annotation .= 'void'; 868 | $bodyMiddle .= $annotation.$this->returnSymbol.$this->tabSymbol.' */'.$this->returnSymbol; 869 | 870 | $bodyStr = $bodyPrefix.$bodyMiddle; 871 | 872 | return $bodyStr; 873 | } 874 | } 875 | -------------------------------------------------------------------------------- /src/tars2php.php: -------------------------------------------------------------------------------- 1 | moduleScan(); 14 | 15 | $fileConverter->moduleParse(); 16 | 17 | class Utils 18 | { 19 | public static $preEnums; 20 | public static $preStructs; 21 | 22 | public static $wholeTypeMap = array( 23 | 'bool' => '\TARS::BOOL', 24 | 'boolean' => '\TARS::BOOL', 25 | 'byte' => '\TARS::CHAR', 26 | 'char' => '\TARS::CHAR', 27 | 'unsigned byte' => '\TARS::UINT8', 28 | 'unsigned char' => '\TARS::UINT8', 29 | 'short' => '\TARS::SHORT', 30 | 'unsigned short' => '\TARS::UINT16', 31 | 'int' => '\TARS::INT32', 32 | 'unsigned int' => '\TARS::UINT32', 33 | 'long' => '\TARS::INT64', 34 | 'float' => '\TARS::FLOAT', 35 | 'double' => '\TARS::DOUBLE', 36 | 'string' => '\TARS::STRING', 37 | 'vector' => 'new \TARS_Vector', 38 | 'map' => 'new \TARS_Map', 39 | ); 40 | 41 | public static $typeMap = array( 42 | 'bool' => '\TARS::BOOL', 43 | 'boolean' => '\TARS::BOOL', 44 | 'byte' => '\TARS::CHAR', 45 | 'char' => '\TARS::CHAR', 46 | 'unsigned byte' => '\TARS::UINT8', 47 | 'unsigned char' => '\TARS::UINT8', 48 | 'short' => '\TARS::SHORT', 49 | 'unsigned short' => '\TARS::UINT16', 50 | 'int' => '\TARS::INT32', 51 | 'unsigned int' => '\TARS::UINT32', 52 | 'long' => '\TARS::INT64', 53 | 'float' => '\TARS::FLOAT', 54 | 'double' => '\TARS::DOUBLE', 55 | 'string' => '\TARS::STRING', 56 | 'vector' => '\TARS::VECTOR', 57 | 'map' => '\TARS::MAP', 58 | 'enum' => '\TARS::UINT8', // 应该不会出现 59 | 'struct' => '\TARS::STRUCT', // 应该不会出现 60 | ); 61 | 62 | public static function getPackMethods($type) 63 | { 64 | $packMethods = [ 65 | 'bool' => 'putBool', 66 | 'boolean' => 'putBool', 67 | 'byte' => 'putChar', 68 | 'char' => 'putChar', 69 | 'unsigned byte' => 'putUInt8', 70 | 'unsigned char' => 'putUInt8', 71 | 'short' => 'putShort', 72 | 'unsigned short' => 'putUInt16', 73 | 'int' => 'putInt32', 74 | 'unsigned int' => 'putUInt32', 75 | 'long' => 'putInt64', 76 | 'float' => 'putFloat', 77 | 'double' => 'putDouble', 78 | 'string' => 'putString', 79 | 'enum' => 'putUInt8', 80 | 'map' => 'putMap', 81 | 'vector' => 'putVector', 82 | 'Bool' => 'putBool', 83 | 'Boolean' => 'putBool', 84 | 'Byte' => 'putChar', 85 | 'Char' => 'putChar', 86 | 'Unsigned byte' => 'putUInt8', 87 | 'Unsigned char' => 'putUInt8', 88 | 'Short' => 'putShort', 89 | 'Unsigned short' => 'putUInt16', 90 | 'Int' => 'putInt32', 91 | 'Unsigned int' => 'putUInt32', 92 | 'Long' => 'putInt64', 93 | 'Float' => 'putFloat', 94 | 'Double' => 'putDouble', 95 | 'String' => 'putString', 96 | 'Enum' => 'putUInt8', 97 | 'Map' => 'putMap', 98 | 'Vector' => 'putVector', 99 | ]; 100 | 101 | if (isset($packMethods[$type])) { 102 | return $packMethods[$type]; 103 | } else { 104 | return 'putStruct'; 105 | } 106 | } 107 | 108 | public static function getUnpackMethods($type) 109 | { 110 | $unpackMethods = [ 111 | 'bool' => 'getBool', 112 | 'boolean' => 'getBool', 113 | 'byte' => 'getChar', 114 | 'char' => 'getChar', 115 | 'unsigned byte' => 'getUInt8', 116 | 'unsigned char' => 'getUInt8', 117 | 'short' => 'getShort', 118 | 'unsigned short' => 'getUInt16', 119 | 'int' => 'getInt32', 120 | 'unsigned int' => 'getUInt32', 121 | 'long' => 'getInt64', 122 | 'float' => 'getFloat', 123 | 'double' => 'getDouble', 124 | 'string' => 'getString', 125 | 'enum' => 'getUInt8', 126 | 'map' => 'getMap', 127 | 'vector' => 'getVector', 128 | 'Bool' => 'getBool', 129 | 'Boolean' => 'getBool', 130 | 'Byte' => 'getChar', 131 | 'Char' => 'getChar', 132 | 'Unsigned byte' => 'getUInt8', 133 | 'Unsigned char' => 'getUInt8', 134 | 'Short' => 'getShort', 135 | 'Unsigned short' => 'getUInt16', 136 | 'Int' => 'getInt32', 137 | 'Unsigned int' => 'getUInt32', 138 | 'Long' => 'getInt64', 139 | 'Float' => 'getFloat', 140 | 'Double' => 'getDouble', 141 | 'String' => 'getString', 142 | 'Enum' => 'getUInt8', 143 | 'Map' => 'getMap', 144 | 'Vector' => 'getVector', 145 | ]; 146 | 147 | if (isset($unpackMethods[strtolower($type)])) { 148 | return $unpackMethods[strtolower($type)]; 149 | } else { 150 | return 'getStruct'; 151 | } 152 | } 153 | 154 | /** 155 | * @param $char 156 | * 157 | * @return int 158 | * 判断是不是tag 159 | */ 160 | public static function isTag($word) 161 | { 162 | if (!is_numeric($word)) { 163 | return false; 164 | } else { 165 | return true; 166 | } 167 | } 168 | 169 | /** 170 | * @param $word 171 | * 172 | * @return bool 173 | * 判断收集到的word是不是 174 | */ 175 | public static function isRequireType($word) 176 | { 177 | return in_array(strtolower($word), ['require', 'optional']); 178 | } 179 | 180 | public static function isBasicType($word) 181 | { 182 | $basicTypes = [ 183 | 'bool', 'boolean', 'byte', 'char', 'unsigned byte', 'unsigned char', 'short', 'unsigned short', 184 | 'int', 'unsigned int', 'long', 'float', 'double', 'string', 'void', 185 | ]; 186 | 187 | return in_array(strtolower($word), $basicTypes); 188 | } 189 | 190 | public static function isEnum($word, $preEnums) 191 | { 192 | return in_array($word, $preEnums); 193 | } 194 | 195 | public static function isMap($word) 196 | { 197 | return strtolower($word) == 'map'; 198 | } 199 | 200 | public static function isStruct($word, $preStructs) 201 | { 202 | return in_array($word, $preStructs); 203 | } 204 | 205 | public static function isVector($word) 206 | { 207 | return strtolower($word) == 'vector'; 208 | } 209 | 210 | public static function isSpace($char) 211 | { 212 | if ($char == ' ' || $char == "\t") { 213 | return true; 214 | } else { 215 | return false; 216 | } 217 | } 218 | 219 | public static function paramTypeMap($paramType) 220 | { 221 | if (self::isBasicType($paramType) || self::isMap($paramType) || self::isVector($paramType)) { 222 | return ''; 223 | } else { 224 | return $paramType; 225 | } 226 | } 227 | 228 | public static function getRealType($type) 229 | { 230 | if (isset(self::$typeMap[strtolower($type)])) { 231 | return self::$typeMap[strtolower($type)]; 232 | } else { 233 | return '\TARS::STRUCT'; 234 | } 235 | } 236 | 237 | public static function inIdentifier($char) 238 | { 239 | return ($char >= 'a' & $char <= 'z') | 240 | ($char >= 'A' & $char <= 'Z') | 241 | ($char >= '0' & $char <= '9') | 242 | ($char == '_'); 243 | } 244 | 245 | public static function abnormalExit($level, $msg) 246 | { 247 | echo "[$level]$msg"."\n"; 248 | exit; 249 | } 250 | 251 | public static function pregMatchByName($name, $line) 252 | { 253 | // 处理第一行,正则匹配出classname 254 | $Tokens = preg_split("/$name/", $line); 255 | 256 | $mathName = $Tokens[1]; 257 | $mathName = trim($mathName, " \r\0\x0B\t\n{"); 258 | 259 | preg_match('/[a-zA-Z][0-9a-zA-Z]/', $mathName, $matches); 260 | if (empty($matches)) { 261 | //Utils::abnormalExit('error',$name.'名称有误'.$line); 262 | } 263 | 264 | return $mathName; 265 | } 266 | 267 | public static function isReturn($char) 268 | { 269 | if ($char == "\n" || $char == '\r' || bin2hex($char) == '0a' || bin2hex($char) == '0b' || 270 | bin2hex($char) == '0c' || bin2hex($char) == '0d') { 271 | return true; 272 | } else { 273 | return false; 274 | } 275 | } 276 | } 277 | 278 | class FileConverter 279 | { 280 | public $moduleName; 281 | public $uniqueName; 282 | public $interfaceName; 283 | public $fromFile; 284 | public $outputDir; 285 | 286 | public $appName; 287 | public $serverName; 288 | public $objName; 289 | public $servantName; 290 | 291 | public $namespaceName; 292 | public $namespacePrefix; 293 | 294 | public $preStructs = []; 295 | public $preEnums = []; 296 | public $preConsts = []; 297 | public $preNamespaceStructs = []; 298 | public $preNamespaceEnums = []; 299 | 300 | public function __construct($config) 301 | { 302 | $this->fromFile = $config['tarsFiles'][0]; 303 | if (empty($config['appName']) || empty($config['serverName']) || empty($config['objName'])) { 304 | Utils::abnormalExit('error', 'appName or serverName or objName empty!'); 305 | } 306 | $this->servantName = $config['appName'].'.'.$config['serverName'].'.'.$config['objName']; 307 | 308 | $this->appName = $config['appName']; 309 | $this->serverName = $config['serverName']; 310 | $this->objName = $config['objName']; 311 | 312 | $this->outputDir = empty($config['dstPath']) ? './' : $config['dstPath'].'/'; 313 | 314 | $pos = strrpos($this->fromFile, '/', -1); 315 | $inputDir = substr($this->fromFile, 0, $pos); 316 | $this->inputDir = $inputDir; 317 | 318 | $this->namespacePrefix = $config['namespacePrefix']; 319 | $this->withServant = $config['withServant']; 320 | 321 | $this->initDir(); 322 | } 323 | 324 | /** 325 | * 首先需要初始化一些文件目录. 326 | * 327 | * @return [type] [description] 328 | */ 329 | public function initDir() 330 | { 331 | if (strtolower(substr(php_uname('a'), 0, 3)) === 'win') { 332 | $this->outputDir = str_replace('/', '\\', $this->outputDir); 333 | $this->fromFile = str_replace('/', '\\', $this->fromFile); 334 | 335 | $this->moduleName = $this->appName.'\\'.$this->serverName.'\\'.$this->objName; 336 | exec('if exist ' . $this->outputDir . $this->moduleName . ' rd /s /q ' . $this->outputDir . $this->moduleName); 337 | 338 | exec('mkdir '.$this->outputDir.$this->moduleName.'\\classes'); 339 | exec('mkdir '.$this->outputDir.$this->moduleName.'\\tars'); 340 | exec('copy '.$this->fromFile.' '.$this->outputDir.$this->moduleName.'\\tars'); 341 | } else { 342 | $this->moduleName = $this->appName.'/'.$this->serverName.'/'.$this->objName; 343 | exec('rm -rf '.$this->outputDir.$this->moduleName); 344 | 345 | exec('mkdir -p '.$this->outputDir.$this->moduleName.'/classes'); 346 | exec('mkdir -p '.$this->outputDir.$this->moduleName.'/tars'); 347 | exec('cp '.$this->fromFile.' '.$this->outputDir.$this->moduleName.'/tars'); 348 | } 349 | 350 | $this->namespaceName = empty($this->namespacePrefix) ? $this->appName.'\\'.$this->serverName.'\\'.$this->objName 351 | : $this->namespacePrefix.'\\'.$this->appName.'\\'.$this->serverName.'\\'.$this->objName; 352 | 353 | $this->uniqueName = $this->appName.'_'.$this->serverName.'_'.$this->objName; 354 | } 355 | 356 | public function usage() 357 | { 358 | echo 'php tars2php.php tars.proto.php'; 359 | } 360 | 361 | public function moduleScan() 362 | { 363 | $fp = fopen($this->fromFile, 'r'); 364 | if (!$fp) { 365 | $this->usage(); 366 | exit; 367 | } 368 | while (($line = fgets($fp, 1024)) !== false) { 369 | 370 | // 判断是否有module 371 | $moduleFlag = strpos($line, 'module'); 372 | if ($moduleFlag !== false) { 373 | $name = Utils::pregMatchByName('module', $line); 374 | $currentModule = $name; 375 | } 376 | 377 | // 判断是否有include 378 | $includeFlag = strpos($line, '#include'); 379 | if ($includeFlag !== false) { 380 | // 找出tars对应的文件名 381 | $tokens = preg_split('/#include/', $line); 382 | $includeFile = trim($tokens[1], "\" \r\n"); 383 | 384 | if (strtolower(substr(php_uname('a'), 0, 3)) === 'win') { 385 | exec('copy '.$includeFile.' '. $this->outputDir . $this->moduleName.'\\tars'); 386 | } else { 387 | exec('cp '.$includeFile.' '. $this->outputDir . $this->moduleName.'/tars'); 388 | } 389 | 390 | $includeParser = new IncludeParser(); 391 | $includeParser->includeScan($includeFile, $this->preEnums, $this->preStructs, 392 | $this->preNamespaceEnums, $this->preNamespaceStructs); 393 | } 394 | 395 | // 如果空行,或者是注释,就直接略过 396 | if (!$line || trim($line) == '' || trim($line)[0] === '/' || trim($line)[0] === '*' || trim($line) === '{') { 397 | continue; 398 | } 399 | 400 | // 正则匹配,发现是在enum中 401 | $enumFlag = strpos($line, 'enum'); 402 | if ($enumFlag !== false) { 403 | $name = Utils::pregMatchByName('enum', $line); 404 | if (!empty($name)) { 405 | $this->preEnums[] = $name; 406 | 407 | // 增加命名空间以备不时之需 408 | if (!empty($currentModule)) { 409 | $this->preNamespaceEnums[] = $currentModule.'::'.$name; 410 | } 411 | 412 | while (($lastChar = fgetc($fp)) != '}') { 413 | continue; 414 | } 415 | } 416 | } 417 | 418 | // 正则匹配,发现是在结构体中 419 | $structFlag = strpos($line, 'struct'); 420 | // 一旦发现了struct,那么持续读到结束为止 421 | if ($structFlag !== false) { 422 | $name = Utils::pregMatchByName('struct', $line); 423 | 424 | if (!empty($name)) { 425 | $this->preStructs[] = $name; 426 | // 增加命名空间以备不时之需 427 | if (!empty($currentModule)) { 428 | $this->preNamespaceStructs[] = $currentModule.'::'.$name; 429 | } 430 | } 431 | } 432 | } 433 | fclose($fp); 434 | } 435 | 436 | public function moduleParse() 437 | { 438 | $fp = fopen($this->fromFile, 'r'); 439 | if (!$fp) { 440 | $this->usage(); 441 | exit; 442 | } 443 | while (($line = fgets($fp, 1024)) !== false) { 444 | 445 | // 判断是否有include 446 | $includeFlag = strpos($line, '#include'); 447 | if ($includeFlag !== false) { 448 | // 找出tars对应的文件名 449 | $tokens = preg_split('/#include/', $line); 450 | $includeFile = trim($tokens[1], "\" \r\n"); 451 | $includeParser = new IncludeParser(); 452 | $includeParser->includeParse($includeFile, $this->preEnums, $this->preStructs, $this->uniqueName, 453 | $this->moduleName, $this->namespaceName, $this->servantName, $this->preNamespaceEnums, $this->preNamespaceStructs, 454 | $this->outputDir); 455 | } 456 | 457 | // 如果空行,或者是注释,就直接略过 458 | if (!$line || trim($line) == '' || trim($line)[0] === '/' || trim($line)[0] === '*') { 459 | continue; 460 | } 461 | 462 | // 正则匹配,发现是在enum中 463 | $enumFlag = strpos($line, 'enum'); 464 | if ($enumFlag !== false) { 465 | // 处理第一行,正则匹配出classname 466 | $enumTokens = preg_split('/enum/', $line); 467 | 468 | $enumName = $enumTokens[1]; 469 | $enumName = trim($enumName, " \r\0\x0B\t\n{"); 470 | 471 | // 判断是否是合法的structName 472 | preg_match('/[a-zA-Z][0-9a-zA-Z]/', $enumName, $matches); 473 | if (empty($matches)) { 474 | Utils::abnormalExit('error', 'Enum名称有误'); 475 | } 476 | 477 | $this->preEnums[] = $enumName; 478 | while (($lastChar = fgetc($fp)) != '}') { 479 | continue; 480 | } 481 | } 482 | 483 | // 正则匹配,发现是在consts中 484 | $constFlag = strpos($line, 'const'); 485 | if ($constFlag !== false) { 486 | // 直接进行正则匹配 487 | Utils::abnormalExit('warning', 'const is not supported, please make sure you deal with them yourself in this version!'); 488 | } 489 | 490 | // 正则匹配,发现是在结构体中 491 | $structFlag = strpos($line, 'struct'); 492 | // 一旦发现了struct,那么持续读到结束为止 493 | if ($structFlag !== false) { 494 | $name = Utils::pregMatchByName('struct', $line); 495 | 496 | $structParser = new StructParser($fp, $line, $this->uniqueName, $this->moduleName, $name, $this->preStructs, 497 | $this->preEnums, $this->namespaceName, $this->preNamespaceEnums, $this->preNamespaceStructs); 498 | $structClassStr = $structParser->parse(); 499 | file_put_contents($this->outputDir.$this->moduleName.'/classes/'.$name.'.php', $structClassStr); 500 | } 501 | 502 | // 正则匹配,发现是在interface中 503 | $interfaceFlag = strpos(strtolower($line), 'interface'); 504 | // 一旦发现了struct,那么持续读到结束为止 505 | if ($interfaceFlag !== false) { 506 | $name = Utils::pregMatchByName('interface', $line); 507 | $interfaceName = $name.'Servant'; 508 | 509 | // 需要区分一下生成server还是client的代码 510 | if ($this->withServant) { 511 | $servantParser = new ServantParser($fp, $line, $this->namespaceName, $this->moduleName, 512 | $interfaceName, $this->preStructs, 513 | $this->preEnums, $this->servantName, $this->preNamespaceEnums, $this->preNamespaceStructs); 514 | $servant = $servantParser->parse(); 515 | file_put_contents($this->outputDir.$this->moduleName.'/'.$interfaceName.'.php', $servant); 516 | } else { 517 | $interfaceParser = new InterfaceParser($fp, $line, $this->namespaceName, $this->moduleName, 518 | $interfaceName, $this->preStructs, 519 | $this->preEnums, $this->servantName, $this->preNamespaceEnums, $this->preNamespaceStructs); 520 | $interfaces = $interfaceParser->parse(); 521 | 522 | // 需要区分同步和异步的两种方式 523 | file_put_contents($this->outputDir.$this->moduleName.'/'.$interfaceName.'.php', $interfaces['syn']); 524 | } 525 | } 526 | } 527 | } 528 | } 529 | 530 | class IncludeParser 531 | { 532 | public function includeScan($includeFile, &$preEnums, &$preStructs, 533 | &$preNamespaceEnums, &$preNamespaceStructs) 534 | { 535 | $fp = fopen($includeFile, 'r'); 536 | if (!$fp) { 537 | echo 'Include file not exit, please check'; 538 | exit; 539 | } 540 | while (($line = fgets($fp, 1024)) !== false) { 541 | // 如果空行,或者是注释,就直接略过 542 | if (!$line || trim($line) == '' || trim($line)[0] === '/' || trim($line)[0] === '*') { 543 | continue; 544 | } 545 | 546 | // 判断是否有module 547 | $moduleFlag = strpos($line, 'module'); 548 | if ($moduleFlag !== false) { 549 | $name = Utils::pregMatchByName('module', $line); 550 | $currentModule = $name; 551 | } 552 | 553 | // 正则匹配,发现是在enum中 554 | $enumFlag = strpos($line, 'enum'); 555 | if ($enumFlag !== false) { 556 | $name = Utils::pregMatchByName('enum', $line); 557 | $preEnums[] = $name; 558 | if (!empty($currentModule)) { 559 | $preNamespaceEnums[] = $currentModule.'::'.$name; 560 | } 561 | while (($lastChar = fgetc($fp)) != '}') { 562 | continue; 563 | } 564 | } 565 | 566 | // 正则匹配,发现是在结构体中 567 | $structFlag = strpos($line, 'struct'); 568 | // 一旦发现了struct,那么持续读到结束为止 569 | if ($structFlag !== false) { 570 | $name = Utils::pregMatchByName('struct', $line); 571 | 572 | $preStructs[] = $name; 573 | if (!empty($currentModule)) { 574 | $preNamespaceStructs[] = $currentModule.'::'.$name; 575 | } 576 | } 577 | } 578 | } 579 | 580 | public function includeParse($includeFile, &$preEnums, &$preStructs, $uniqueName, $moduleName, $namespaceName, $servantName, 581 | &$preNamespaceEnums, &$preNamespaceStructs, $outputDir) 582 | { 583 | $fp = fopen($includeFile, 'r'); 584 | if (!$fp) { 585 | echo 'Include file not exit, please check'; 586 | exit; 587 | } 588 | while (($line = fgets($fp, 1024)) !== false) { 589 | // 如果空行,或者是注释,就直接略过 590 | if (!$line || trim($line) == '' || trim($line)[0] === '/' || trim($line)[0] === '*') { 591 | continue; 592 | } 593 | 594 | // 正则匹配,发现是在consts中 595 | $constFlag = strpos($line, 'const'); 596 | if ($constFlag !== false) { 597 | // 直接进行正则匹配 598 | echo 'CONST is not supported, please make sure you deal with them yourself in this version!'; 599 | } 600 | 601 | // 正则匹配,发现是在结构体中 602 | $structFlag = strpos($line, 'struct'); 603 | // 一旦发现了struct,那么持续读到结束为止 604 | if ($structFlag !== false) { 605 | $name = Utils::pregMatchByName('struct', $line); 606 | 607 | $structParser = new StructParser($fp, $line, $uniqueName, $moduleName, $name, $preStructs, 608 | $preEnums, $namespaceName, $preNamespaceEnums, $preNamespaceStructs); 609 | $structClassStr = $structParser->parse(); 610 | file_put_contents($outputDir.$moduleName.'/classes/'.$name.'.php', $structClassStr); 611 | } 612 | 613 | // 正则匹配,发现是在interface中 614 | $interfaceFlag = strpos(strtolower($line), 'interface'); 615 | // 一旦发现了struct,那么持续读到结束为止 616 | if ($interfaceFlag !== false) { 617 | $name = Utils::pregMatchByName('interface', $line); 618 | 619 | if (in_array($name, $preStructs)) { 620 | $name .= 'Servant'; 621 | } 622 | 623 | $interfaceParser = new InterfaceParser($fp, $line, $namespaceName, $moduleName, 624 | $name, $preStructs, 625 | $preEnums, $servantName, $preNamespaceEnums, $preNamespaceStructs); 626 | $interfaces = $interfaceParser->parse(); 627 | 628 | // 需要区分同步和异步的两种方式 629 | file_put_contents($outputDir.$moduleName.'/'.$name.'.php', $interfaces['syn']); 630 | } 631 | } 632 | } 633 | } 634 | 635 | class InterfaceParser 636 | { 637 | public $namespaceName; 638 | public $moduleName; 639 | public $interfaceName; 640 | public $asInterfaceName; 641 | 642 | public $state; 643 | 644 | // 这个结构体,可能会引用的部分,包括其他的结构体、枚举类型、常量 645 | public $useStructs = []; 646 | public $extraUse; 647 | public $preStructs; 648 | public $preEnums; 649 | 650 | public $preNamespaceStructs; 651 | public $preNamespaceEnums; 652 | 653 | public $returnSymbol = "\n"; 654 | public $doubleReturn = "\n\n"; 655 | public $tabSymbol = "\t"; 656 | public $doubleTab = "\t\t"; 657 | public $tripleTab = "\t\t\t"; 658 | public $quardupleTab = "\t\t\t\t"; 659 | 660 | public $extraContructs = ''; 661 | public $extraExtInit = ''; 662 | 663 | public $consts = ''; 664 | public $variables = ''; 665 | public $fields = ''; 666 | 667 | public $funcSet = ''; 668 | 669 | public $servantName; 670 | 671 | public function __construct($fp, $line, $namespaceName, $moduleName, 672 | $interfaceName, $preStructs, 673 | $preEnums, $servantName, $preNamespaceEnums, $preNamespaceStructs) 674 | { 675 | $this->fp = $fp; 676 | $this->namespaceName = $namespaceName; 677 | $this->moduleName = $moduleName; 678 | $this->preStructs = $preStructs; 679 | $this->preEnums = $preEnums; 680 | $this->interfaceName = $interfaceName; 681 | $this->servantName = $servantName; 682 | 683 | $this->extraUse = ''; 684 | $this->useStructs = []; 685 | 686 | $this->preNamespaceEnums = $preNamespaceEnums; 687 | $this->preNamespaceStructs = $preNamespaceStructs; 688 | } 689 | 690 | public function copyAnnotation() 691 | { 692 | // 再读入一个字符 693 | $nextChar = fgetc($this->fp); 694 | // 第一种 695 | if ($nextChar == '/') { 696 | while (1) { 697 | $tmpChar = fgetc($this->fp); 698 | 699 | if ($tmpChar == "\n") { 700 | $this->state = 'lineEnd'; 701 | break; 702 | } 703 | } 704 | 705 | return; 706 | } elseif ($nextChar == '*') { 707 | while (1) { 708 | $tmpChar = fgetc($this->fp); 709 | 710 | if ($tmpChar === false) { 711 | Utils::abnormalExit('error', '注释换行错误,请检查'.$tmpChar); 712 | } elseif ($tmpChar === "\n") { 713 | } elseif (($tmpChar) === '*') { 714 | $nextnextChar = fgetc($this->fp); 715 | if ($nextnextChar == '/') { 716 | return; 717 | } else { 718 | $pos = ftell($this->fp); 719 | fseek($this->fp, $pos - 1); 720 | } 721 | } 722 | } 723 | } 724 | // 注释不正常 725 | else { 726 | Utils::abnormalExit('error', '注释换行错误,请检查'.$nextChar); 727 | } 728 | } 729 | 730 | public function getFileHeader($prefix = '') 731 | { 732 | return "namespaceName.$prefix.';'.$this->doubleReturn. 733 | 'use Tars\\client\\CommunicatorConfig;'.$this->returnSymbol. 734 | 'use Tars\\client\\Communicator;'.$this->returnSymbol. 735 | 'use Tars\\client\\RequestPacket;'.$this->returnSymbol. 736 | 'use Tars\\client\\TUPAPIWrapper;'.$this->returnSymbol. 737 | $this->returnSymbol; 738 | } 739 | 740 | public function getInterfaceBasic() 741 | { 742 | return $this->tabSymbol.'protected $_communicator;'.$this->returnSymbol. 743 | $this->tabSymbol.'protected $_iVersion;'.$this->returnSymbol. 744 | $this->tabSymbol.'protected $_iTimeout;'.$this->returnSymbol. 745 | $this->tabSymbol."public \$_servantName = \"$this->servantName\";".$this->returnSymbol. 746 | $this->tabSymbol."public \$_contexts = [];".$this->returnSymbol. 747 | $this->tabSymbol."public \$_statuses = [];".$this->doubleReturn. 748 | $this->tabSymbol.'public function __construct(CommunicatorConfig $config) {'.$this->returnSymbol. 749 | 750 | $this->doubleTab.'try {'.$this->returnSymbol. 751 | $this->tripleTab.'$config->setServantName($this->_servantName);'.$this->returnSymbol. 752 | $this->tripleTab.'$this->_communicator = new Communicator($config);'.$this->returnSymbol. 753 | $this->tripleTab.'$this->_iVersion = $config->getIVersion();'.$this->returnSymbol. 754 | $this->tripleTab.'$this->_iTimeout = empty($config->getAsyncInvokeTimeout())?2:$config->getAsyncInvokeTimeout();'.$this->returnSymbol. 755 | $this->doubleTab.'} catch (\\Exception $e) {'.$this->returnSymbol. 756 | $this->tripleTab.'throw $e;'.$this->returnSymbol. 757 | $this->doubleTab.'}'.$this->returnSymbol. 758 | $this->tabSymbol.'}'.$this->doubleReturn; 759 | } 760 | 761 | public function parse() 762 | { 763 | while ($this->state != 'end') { 764 | $this->state = 'init'; 765 | $this->InterfaceFuncParseLine(); 766 | } 767 | 768 | $interfaceClass = $this->getFileHeader('').$this->extraUse.'class '.$this->interfaceName.' {'.$this->returnSymbol; 769 | 770 | $interfaceClass .= $this->getInterfaceBasic(); 771 | 772 | $interfaceClass .= $this->funcSet; 773 | 774 | $interfaceClass .= '}'.$this->doubleReturn; 775 | 776 | return [ 777 | 'syn' => $interfaceClass, 778 | ]; 779 | } 780 | 781 | /** 782 | * @param $fp 783 | * @param $line 784 | * 这里必须要引入状态机了 785 | */ 786 | public function InterfaceFuncParseLine() 787 | { 788 | $line = ''; 789 | $this->state = 'init'; 790 | while (1) { 791 | if ($this->state == 'init') { 792 | $char = fgetc($this->fp); 793 | 794 | // 有可能是换行 795 | if ($char == '{' || Utils::isReturn($char)) { 796 | continue; 797 | } 798 | // 遇到了注释会用贪婪算法全部处理完,同时填充到struct的类里面去 799 | elseif ($char == '/') { 800 | $this->copyAnnotation(); 801 | break; 802 | } elseif (Utils::inIdentifier($char)) { 803 | $this->state = 'identifier'; 804 | $line .= $char; 805 | } 806 | // 终止条件之1,宣告struct结束 807 | elseif ($char == '}') { 808 | // 需要贪心的读到"\n"为止 809 | while (($lastChar = fgetc($this->fp)) != "\n" && ($lastChar !== false)) { 810 | continue; 811 | } 812 | $this->state = 'end'; 813 | break; 814 | } 815 | } elseif ($this->state == 'identifier') { 816 | $char = fgetc($this->fp); 817 | 818 | if ($char == '/') { 819 | $this->copyAnnotation(); 820 | } elseif ($char == ';') { 821 | $line .= $char; 822 | break; 823 | } 824 | // 终止条件之2,同样宣告interface结束 825 | elseif ($char == '}') { 826 | // 需要贪心的读到"\n"为止 827 | while (($lastChar = fgetc($this->fp)) != "\n") { 828 | continue; 829 | } 830 | $this->state = 'end'; 831 | } elseif (Utils::isReturn($char)) { 832 | continue; 833 | } elseif ($char == ')') { 834 | $line .= $char; 835 | // 需要贪心的读到"\n"为止 836 | while (($lastChar = fgetc($this->fp)) != "\n") { 837 | continue; 838 | } 839 | $this->state = 'lineEnd'; 840 | } else { 841 | $line .= $char; 842 | } 843 | } elseif ($this->state == 'lineEnd') { 844 | $char = fgetc($this->fp); 845 | if ($char == '}') { 846 | // 需要贪心的读到"\n"为止 847 | while (($lastChar = fgetc($this->fp)) != "\n") { 848 | continue; 849 | } 850 | $this->state = 'end'; 851 | } 852 | break; 853 | } elseif ($this->state == 'end') { 854 | break; 855 | } 856 | } 857 | if (empty($line)) { 858 | return; 859 | } 860 | 861 | $line = trim($line); 862 | // 如果空行,或者是注释,或者是大括号就直接略过 863 | if (!$line || $line[0] === '/' || $line[0] === '*' || $line === '{') { 864 | return; 865 | } 866 | 867 | $endFlag = strpos($line, '};'); 868 | if ($endFlag !== false) { 869 | $this->state = 'end'; 870 | 871 | return; 872 | } 873 | 874 | $endFlag = strpos($line, '}'); 875 | if ($endFlag !== false) { 876 | $this->state = 'end'; 877 | 878 | return; 879 | } 880 | 881 | // 有必要先分成三个部分,返回类型、接口名、参数列表 882 | $tokens = preg_split('/\(/', $line, 2); 883 | $mix = trim($tokens[0]); 884 | $rest = $tokens[1]; 885 | 886 | $pices = preg_split('/\s+/', $mix); 887 | 888 | $funcName = $pices[count($pices) - 1]; 889 | 890 | $returnType = implode('', array_slice($pices, 0, count($pices) - 1)); 891 | 892 | $state = 'init'; 893 | $word = ''; 894 | 895 | $params = []; 896 | 897 | for ($i = 0; $i < strlen($rest); ++$i) { 898 | $char = $rest[$i]; 899 | 900 | if ($state == 'init') { 901 | // 有可能是换行 902 | if ($char == '(' || Utils::isSpace($char)) { 903 | continue; 904 | } elseif ($char == "\n") { 905 | break; 906 | } elseif (Utils::inIdentifier($char)) { 907 | $state = 'identifier'; 908 | $word .= $char; 909 | } 910 | // 终止条件之1,宣告interface结束 911 | elseif ($char == ')') { 912 | break; 913 | } else { 914 | Utils::abnormalExit('error', 'Interface:'.$this->interfaceName.'内格式错误,请更正tars'); 915 | } 916 | } elseif ($state == 'identifier') { 917 | if ($char == ',') { 918 | $params[] = $word; 919 | $state = 'init'; 920 | $word = ''; 921 | continue; 922 | } 923 | // 标志着map和vector的开始,不等到'>'的结束不罢休 924 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 925 | elseif ($char == '<') { 926 | $mapVectorStack = []; 927 | $word .= $char; 928 | array_push($mapVectorStack, '<'); 929 | while (!empty($mapVectorStack)) { 930 | $moreChar = $rest[$i + 1]; 931 | $word .= $moreChar; 932 | if ($moreChar == '<') { 933 | array_push($mapVectorStack, '<'); 934 | } elseif ($moreChar == '>') { 935 | array_pop($mapVectorStack); 936 | } 937 | ++$i; 938 | } 939 | continue; 940 | } elseif ($char == ')') { 941 | $params[] = $word; 942 | break; 943 | } elseif ($char == ';') { 944 | continue; 945 | } 946 | // 终止条件之2,同样宣告struct结束 947 | elseif ($char == '}') { 948 | $state = 'end'; 949 | } elseif ($char == "\n") { 950 | break; 951 | } else { 952 | $word .= $char; 953 | } 954 | } elseif ($state == 'lineEnd') { 955 | break; 956 | } elseif ($state == 'end') { 957 | break; 958 | } 959 | } 960 | $this->writeInterfaceLine($returnType, $funcName, $params); 961 | } 962 | 963 | /** 964 | * @param $wholeType 965 | * 通过完整的类型获取vector的扩展类型 966 | * vector => new \TARS_VECTOR(new CateObj()) 967 | * vector => new \TARS_VECTOR(\TARS::STRING) 968 | * vector> => new \TARS_VECTOR(new \TARS_MAP(\TARS_MAP,new CateObj())) 969 | */ 970 | public function getExtType($wholeType, $valueName) 971 | { 972 | $state = 'init'; 973 | $word = ''; 974 | $extType = ''; 975 | 976 | for ($i = 0; $i < strlen($wholeType); ++$i) { 977 | $char = $wholeType[$i]; 978 | if ($state == 'init') { 979 | // 如果遇到了空格 980 | if (Utils::isSpace($char)) { 981 | continue; 982 | } 983 | // 回车是停止符号 984 | elseif (Utils::inIdentifier($char)) { 985 | $state = 'indentifier'; 986 | $word .= $char; 987 | } elseif (Utils::isReturn($char)) { 988 | break; 989 | } elseif ($char == '>') { 990 | $extType .= ')'; 991 | continue; 992 | } 993 | } elseif ($state == 'indentifier') { 994 | if ($char == '<') { 995 | // 替换word,替换< 恢复初始状态 996 | $tmp = $this->VecMapReplace($word); 997 | $extType .= $tmp; 998 | $extType .= '('; 999 | $word = ''; 1000 | $state = 'init'; 1001 | } elseif ($char == '>') { 1002 | // 替换word,替换> 恢复初始状态 1003 | // 替换word,替换< 恢复初始状态 1004 | $tmp = $this->VecMapReplace($word); 1005 | $extType .= $tmp; 1006 | $extType .= ')'; 1007 | $word = ''; 1008 | $state = 'init'; 1009 | } elseif ($char == ',') { 1010 | // 替换word,替换, 恢复初始状态 1011 | // 替换word,替换< 恢复初始状态 1012 | $tmp = $this->VecMapReplace($word); 1013 | $extType .= $tmp; 1014 | $extType .= ','; 1015 | $word = ''; 1016 | $state = 'init'; 1017 | } else { 1018 | $word .= $char; 1019 | continue; 1020 | } 1021 | } 1022 | } 1023 | 1024 | return $extType; 1025 | } 1026 | 1027 | public function VecMapReplace($word) 1028 | { 1029 | $word = trim($word); 1030 | // 遍历所有的类型 1031 | foreach (Utils::$wholeTypeMap as $key => $value) { 1032 | if (Utils::isStruct($word, $this->preStructs)) { 1033 | if (!in_array($word, $this->useStructs)) { 1034 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1035 | $this->useStructs[] = $word; 1036 | } 1037 | 1038 | $word = 'new '.$word.'()'; 1039 | } elseif (in_array($word, $this->preNamespaceStructs)) { 1040 | $words = explode('::', $word); 1041 | $word = $words[1]; 1042 | if (!in_array($word, $this->useStructs)) { 1043 | $this->extraUse .= 'use protocol\\'.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1044 | $this->useStructs[] = $word; 1045 | } 1046 | 1047 | $word = 'new '.$word.'()'; 1048 | break; 1049 | } elseif (in_array($word, $this->preEnums)) { 1050 | $word = 'int'; 1051 | } else { 1052 | $word = preg_replace('/\b'.$key.'\b/', $value, $word); 1053 | } 1054 | } 1055 | 1056 | return $word; 1057 | } 1058 | 1059 | public function paramParser($params) 1060 | { 1061 | 1062 | // 输入和输出的参数全部捋一遍 1063 | $inParams = []; 1064 | $outParams = []; 1065 | foreach ($params as $param) { 1066 | $state = 'init'; 1067 | $word = ''; 1068 | $wholeType = ''; 1069 | $paramType = 'in'; 1070 | $type = ''; 1071 | $mapVectorState = false; 1072 | 1073 | for ($i = 0; $i < strlen($param); ++$i) { 1074 | $char = $param[$i]; 1075 | if ($state == 'init') { 1076 | // 有可能是换行 1077 | if (Utils::isSpace($char)) { 1078 | continue; 1079 | } elseif ($char == "\n") { 1080 | break; 1081 | } elseif (Utils::inIdentifier($char)) { 1082 | $state = 'identifier'; 1083 | $word .= $char; 1084 | } else { 1085 | Utils::abnormalExit('error', 'Interface:'.$this->interfaceName.'内格式错误,请更正tars'); 1086 | } 1087 | } elseif ($state == 'identifier') { 1088 | // 如果遇到了space,需要检查是不是在map或vector的类型中,如果当前积累的word并不合法 1089 | // 并且又不是处在vector或map的前置状态下的话,那么就是出错了 1090 | if (Utils::isSpace($char)) { 1091 | if ($word == 'out') { 1092 | $paramType = $word; 1093 | $state = 'init'; 1094 | $word = ''; 1095 | } elseif (Utils::isBasicType($word)) { 1096 | $type = $word; 1097 | $state = 'init'; 1098 | $word = ''; 1099 | } elseif (Utils::isStruct($word, $this->preStructs)) { 1100 | 1101 | // 同时要把它增加到本Interface的依赖中 1102 | if (!in_array($word, $this->useStructs)) { 1103 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1104 | $this->useStructs[] = $word; 1105 | } 1106 | 1107 | $type = $word; 1108 | $state = 'init'; 1109 | $word = ''; 1110 | } elseif (Utils::isEnum($word, $this->preEnums)) { 1111 | $type = 'int'; 1112 | $state = 'init'; 1113 | $word = ''; 1114 | } elseif (in_array($word, $this->preNamespaceStructs)) { 1115 | $word = explode('::', $word); 1116 | $word = $word[1]; 1117 | // 同时要把它增加到本Interface的依赖中 1118 | if (!in_array($word, $this->useStructs)) { 1119 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1120 | $this->useStructs[] = $word; 1121 | } 1122 | 1123 | $type = $word; 1124 | $state = 'init'; 1125 | $word = ''; 1126 | } elseif (in_array($word, $this->preNamespaceEnums)) { 1127 | $type = 'int'; 1128 | $state = 'init'; 1129 | $word = ''; 1130 | } elseif (Utils::isMap($word)) { 1131 | $mapVectorState = true; 1132 | } elseif (Utils::isVector($word)) { 1133 | $mapVectorState = true; 1134 | } else { 1135 | // 读到了vector和map中间的空格,还没读完 1136 | if ($mapVectorState) { 1137 | continue; 1138 | } 1139 | // 否则剩余的部分应该就是值和默认值 1140 | else { 1141 | if (!empty($word)) { 1142 | $valueName = $word; 1143 | } 1144 | $state = 'init'; 1145 | $word = ''; 1146 | } 1147 | } 1148 | } 1149 | // 标志着map和vector的开始,不等到'>'的结束不罢休 1150 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 1151 | elseif ($char == '<') { 1152 | // 贪婪的向后,直到找出所有的'>' 1153 | $type = $word; 1154 | // 还会有一个wholeType,表示完整的部分 1155 | $mapVectorStack = []; 1156 | $wholeType = $type; 1157 | $wholeType .= '<'; 1158 | array_push($mapVectorStack, '<'); 1159 | while (!empty($mapVectorStack)) { 1160 | $moreChar = $param[$i + 1]; 1161 | $wholeType .= $moreChar; 1162 | if ($moreChar == '<') { 1163 | array_push($mapVectorStack, '<'); 1164 | } elseif ($moreChar == '>') { 1165 | array_pop($mapVectorStack); 1166 | } 1167 | ++$i; 1168 | } 1169 | 1170 | $state = 'init'; 1171 | $word = ''; 1172 | } else { 1173 | $word .= $char; 1174 | } 1175 | } 1176 | } 1177 | 1178 | if (!empty($word)) { 1179 | $valueName = $word; 1180 | } 1181 | 1182 | if ($paramType == 'in') { 1183 | $inParams[] = [ 1184 | 'type' => $type, 1185 | 'wholeType' => $wholeType, 1186 | 'valueName' => $valueName, 1187 | ]; 1188 | } else { 1189 | $outParams[] = [ 1190 | 'type' => $type, 1191 | 'wholeType' => $wholeType, 1192 | 'valueName' => $valueName, 1193 | ]; 1194 | } 1195 | } 1196 | 1197 | return [ 1198 | 'in' => $inParams, 1199 | 'out' => $outParams, 1200 | ]; 1201 | } 1202 | 1203 | public function returnParser($returnType) 1204 | { 1205 | if (Utils::isStruct($returnType, $this->preStructs)) { 1206 | if (!in_array($returnType, $this->useStructs)) { 1207 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$returnType.';'.$this->returnSymbol; 1208 | $this->useStructs[] = $returnType; 1209 | } 1210 | $returnInfo = [ 1211 | 'type' => $returnType, 1212 | 'wholeType' => $returnType, 1213 | 'valueName' => $returnType, 1214 | ]; 1215 | 1216 | return $returnInfo; 1217 | } elseif (Utils::isBasicType($returnType)) { 1218 | $returnInfo = [ 1219 | 'type' => $returnType, 1220 | 'wholeType' => $returnType, 1221 | 'valueName' => $returnType, 1222 | ]; 1223 | 1224 | return $returnInfo; 1225 | } elseif (Utils::isEnum($returnType, $this->preEnums)) { 1226 | $returnInfo = [ 1227 | 'type' => 'int', 1228 | 'wholeType' => 'int', 1229 | 'valueName' => 'int' 1230 | ]; 1231 | return $returnInfo; 1232 | } 1233 | 1234 | $state = 'init'; 1235 | $word = ''; 1236 | $wholeType = ''; 1237 | $type = ''; 1238 | $mapVectorState = false; 1239 | $valueName = ''; 1240 | 1241 | for ($i = 0; $i < strlen($returnType); ++$i) { 1242 | $char = $returnType[$i]; 1243 | if ($state == 'init') { 1244 | // 有可能是换行 1245 | if (Utils::isSpace($char)) { 1246 | continue; 1247 | } elseif ($char == "\n") { 1248 | break; 1249 | } elseif (Utils::inIdentifier($char)) { 1250 | $state = 'identifier'; 1251 | $word .= $char; 1252 | } else { 1253 | Utils::abnormalExit('error', 'Interface内格式错误,请更正tars'); 1254 | } 1255 | } elseif ($state == 'identifier') { 1256 | // 如果遇到了space,需要检查是不是在map或vector的类型中,如果当前积累的word并不合法 1257 | // 并且又不是处在vector或map的前置状态下的话,那么就是出错了 1258 | //echo "[debug][state={$this->state}]word:".$word."\n"; 1259 | if (Utils::isSpace($char)) { 1260 | if (Utils::isBasicType($word)) { 1261 | $type = $word; 1262 | $state = 'init'; 1263 | $word = ''; 1264 | } elseif (Utils::isStruct($word, $this->preStructs)) { 1265 | 1266 | // 同时要把它增加到本Interface的依赖中 1267 | if (!in_array($word, $this->useStructs)) { 1268 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1269 | $this->useStructs[] = $word; 1270 | } 1271 | 1272 | $type = $word; 1273 | $state = 'init'; 1274 | $word = ''; 1275 | } elseif (Utils::isEnum($word, $this->preEnums)) { 1276 | $type = 'int'; 1277 | $state = 'init'; 1278 | $word = ''; 1279 | } elseif (in_array($word, $this->preNamespaceStructs)) { 1280 | $word = explode('::', $word); 1281 | $word = $word[1]; 1282 | // 同时要把它增加到本Interface的依赖中 1283 | if (!in_array($word, $this->useStructs)) { 1284 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 1285 | $this->useStructs[] = $word; 1286 | } 1287 | 1288 | $type = $word; 1289 | $state = 'init'; 1290 | $word = ''; 1291 | } elseif (in_array($word, $this->preNamespaceEnums)) { 1292 | $type = 'int'; 1293 | $state = 'init'; 1294 | $word = ''; 1295 | } elseif (Utils::isMap($word)) { 1296 | $mapVectorState = true; 1297 | } elseif (Utils::isVector($word)) { 1298 | $mapVectorState = true; 1299 | } else { 1300 | // 读到了vector和map中间的空格,还没读完 1301 | if ($mapVectorState) { 1302 | continue; 1303 | } 1304 | // 否则剩余的部分应该就是值和默认值 1305 | else { 1306 | if (!empty($word)) { 1307 | $valueName = $word; 1308 | } 1309 | $state = 'init'; 1310 | $word = ''; 1311 | } 1312 | } 1313 | } 1314 | // 标志着map和vector的开始,不等到'>'的结束不罢休 1315 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 1316 | elseif ($char == '<') { 1317 | // 贪婪的向后,直到找出所有的'>' 1318 | $type = $word; 1319 | // 还会有一个wholeType,表示完整的部分 1320 | $mapVectorStack = []; 1321 | $wholeType = $type; 1322 | $wholeType .= '<'; 1323 | array_push($mapVectorStack, '<'); 1324 | while (!empty($mapVectorStack)) { 1325 | $moreChar = $returnType[$i + 1]; 1326 | $wholeType .= $moreChar; 1327 | if ($moreChar == '<') { 1328 | array_push($mapVectorStack, '<'); 1329 | } elseif ($moreChar == '>') { 1330 | array_pop($mapVectorStack); 1331 | } 1332 | ++$i; 1333 | } 1334 | 1335 | $state = 'init'; 1336 | $word = ''; 1337 | } else { 1338 | $word .= $char; 1339 | } 1340 | } 1341 | } 1342 | 1343 | $returnInfo = [ 1344 | 'type' => $type, 1345 | 'wholeType' => $wholeType, 1346 | 'valueName' => $valueName, 1347 | ]; 1348 | 1349 | return $returnInfo; 1350 | } 1351 | /** 1352 | * @param $tag 1353 | * @param $requireType 1354 | * @param $type 1355 | * @param $name 1356 | * @param $wholeType 1357 | * @param $defaultValue 1358 | */ 1359 | public function writeInterfaceLine($returnType, $funcName, $params) 1360 | { 1361 | $result = $this->paramParser($params); 1362 | $inParams = $result['in']; 1363 | $outParams = $result['out']; 1364 | 1365 | // 处理通用的头部 1366 | $funcHeader = $this->generateFuncHeader($funcName, $inParams, $outParams); 1367 | $returnInfo = $this->returnParser($returnType); 1368 | 1369 | $funcBodyArr = $this->generateFuncBody($inParams, $outParams, $returnInfo); 1370 | $synFuncBody = $funcBodyArr['syn']; 1371 | 1372 | $funcTail = $this->tabSymbol.'}'.$this->doubleReturn; 1373 | 1374 | $this->funcSet .= $funcHeader.$synFuncBody.$funcTail; 1375 | } 1376 | 1377 | /** 1378 | * @param $funcName 1379 | * @param $inParams 1380 | * @param $outParams 1381 | * 1382 | * @return string 1383 | */ 1384 | public function generateFuncHeader($funcName, $inParams, $outParams) 1385 | { 1386 | $paramsStr = ''; 1387 | foreach ($inParams as $param) { 1388 | $paramPrefix = Utils::paramTypeMap($param['type']); 1389 | $paramSuffix = '$'.$param['valueName']; 1390 | $paramsStr .= !empty($paramPrefix) ? $paramPrefix.' '.$paramSuffix.',' : $paramSuffix.','; 1391 | } 1392 | 1393 | foreach ($outParams as $param) { 1394 | $paramPrefix = Utils::paramTypeMap($param['type']); 1395 | $paramSuffix = '&$'.$param['valueName']; 1396 | $paramsStr .= !empty($paramPrefix) ? $paramPrefix.' '.$paramSuffix.',' : $paramSuffix.','; 1397 | } 1398 | 1399 | $paramsStr = trim($paramsStr, ','); 1400 | $paramsStr .= ') {'.$this->returnSymbol; 1401 | 1402 | $funcHeader = $this->tabSymbol.'public function '.$funcName.'('.$paramsStr; 1403 | 1404 | return $funcHeader; 1405 | } 1406 | 1407 | /** 1408 | * @param $funcName 1409 | * @param $inParams 1410 | * @param $outParams 1411 | * 生成函数的包体 1412 | */ 1413 | public function generateFuncBody($inParams, $outParams, $returnInfo) 1414 | { 1415 | $bodyPrefix = $this->doubleTab.'try {'.$this->returnSymbol; 1416 | 1417 | $bodySuffix = $this->doubleTab.'catch (\\Exception $e) {'.$this->returnSymbol. 1418 | $this->tripleTab.'throw $e;'.$this->returnSymbol. 1419 | $this->doubleTab.'}'.$this->returnSymbol; 1420 | 1421 | $bodyMiddle = $this->tripleTab.'$requestPacket = new RequestPacket();'.$this->returnSymbol. 1422 | $this->tripleTab.'$requestPacket->_iVersion = $this->_iVersion;'.$this->returnSymbol. 1423 | $this->tripleTab.'$requestPacket->_funcName = __FUNCTION__;'.$this->returnSymbol. 1424 | $this->tripleTab.'$requestPacket->_servantName = $this->_servantName;'.$this->returnSymbol. 1425 | $this->tripleTab.'$requestPacket->_contexts = $this->_contexts;'.$this->returnSymbol. 1426 | $this->tripleTab.'$requestPacket->_statuses = $this->_statuses;'.$this->returnSymbol. 1427 | $this->tripleTab.'$encodeBufs = [];'.$this->doubleReturn; 1428 | 1429 | $commonPrefix = '$__buffer = TUPAPIWrapper::'; 1430 | 1431 | $index = 0; 1432 | foreach ($inParams as $param) { 1433 | ++$index; 1434 | $type = $param['type']; 1435 | 1436 | $packMethod = Utils::getPackMethods($type); 1437 | $valueName = $param['valueName']; 1438 | 1439 | // 判断如果是vector需要特别的处理 1440 | if (Utils::isVector($type)) { 1441 | $vecFill = $this->tripleTab.'$'.$valueName.'_vec = '.$this->getExtType($param['wholeType'], $valueName).';'.$this->returnSymbol. 1442 | $this->tripleTab.'foreach($'.$valueName.' as '.'$single'.$valueName.') {'.$this->returnSymbol. 1443 | $this->quardupleTab.'$'.$valueName.'_vec->pushBack($single'.$valueName.');'.$this->returnSymbol. 1444 | $this->tripleTab.'}'.$this->returnSymbol; 1445 | $bodyMiddle .= $vecFill; 1446 | $bodyMiddle .= $this->tripleTab.$commonPrefix.$packMethod.'("'.$valueName."\",{$index},\$".$valueName.'_vec,$this->_iVersion);'.$this->returnSymbol; 1447 | } 1448 | 1449 | // 判断如果是map需要特别的处理 1450 | elseif (Utils::isMap($type)) { 1451 | $mapFill = $this->tripleTab.'$'.$valueName.'_map = '.$this->getExtType($param['wholeType'], $valueName).';'.$this->returnSymbol. 1452 | $this->tripleTab.'foreach($'.$valueName.' as '.'$key => $value) {'.$this->returnSymbol. 1453 | $this->quardupleTab.'$'.$valueName.'_map->pushBack([$key => $value]);'.$this->returnSymbol. 1454 | $this->tripleTab.'}'.$this->returnSymbol; 1455 | $bodyMiddle .= $mapFill; 1456 | $bodyMiddle .= $this->tripleTab.$commonPrefix.$packMethod.'("'.$valueName."\",{$index},\$".$valueName.'_map,$this->_iVersion);'.$this->returnSymbol; 1457 | } 1458 | // 针对struct,需要额外的use过程 1459 | elseif (Utils::isStruct($type, $this->preStructs)) { 1460 | if (!in_array($type, $this->useStructs)) { 1461 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$param['type'].';'.$this->returnSymbol; 1462 | $this->useStructs[] = $param['type']; 1463 | } 1464 | $bodyMiddle .= $this->tripleTab.$commonPrefix.$packMethod.'("'.$valueName."\",{$index},\$".$valueName.',$this->_iVersion);'.$this->returnSymbol; 1465 | } else { 1466 | $bodyMiddle .= $this->tripleTab.$commonPrefix.$packMethod.'("'.$valueName."\",{$index},\$".$valueName.',$this->_iVersion);'.$this->returnSymbol; 1467 | } 1468 | 1469 | $bodyMiddle .= $this->tripleTab."\$encodeBufs['{$valueName}'] = \$__buffer;".$this->returnSymbol; 1470 | } 1471 | 1472 | $bodyMiddle .= $this->tripleTab.'$requestPacket->_encodeBufs = $encodeBufs;'. 1473 | $this->doubleReturn; 1474 | 1475 | $bodyMiddle .= $this->tripleTab.'$sBuffer = $this->_communicator->invoke($requestPacket,$this->_iTimeout);'.$this->doubleReturn; 1476 | 1477 | foreach ($outParams as $param) { 1478 | ++$index; 1479 | 1480 | $type = $param['type']; 1481 | 1482 | $unpackMethods = Utils::getUnpackMethods($type); 1483 | $name = $param['valueName']; 1484 | 1485 | if (Utils::isBasicType($type)) { 1486 | $bodyMiddle .= $this->tripleTab."\$$name = TUPAPIWrapper::".$unpackMethods.'("'.$name."\",{$index},\$sBuffer,\$this->_iVersion);".$this->returnSymbol; 1487 | } else { 1488 | // 判断如果是vector需要特别的处理 1489 | if (Utils::isVector($type) || Utils::isMap($type)) { 1490 | $bodyMiddle .= $this->tripleTab."\$$name = TUPAPIWrapper::".$unpackMethods.'("'.$name."\",{$index},".$this->getExtType($param['wholeType'], $name).',$sBuffer,$this->_iVersion);'.$this->returnSymbol; 1491 | } 1492 | // 如果是struct 1493 | elseif (Utils::isStruct($type, $this->preStructs)) { 1494 | $bodyMiddle .= $this->tripleTab.'$ret = TUPAPIWrapper::'.$unpackMethods.'("'.$name."\",{$index},\$$name,\$sBuffer,\$this->_iVersion);".$this->returnSymbol; 1495 | 1496 | if (!in_array($type, $this->useStructs)) { 1497 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$param['type'].';'.$this->returnSymbol; 1498 | $this->useStructs[] = $param['type']; 1499 | } 1500 | } 1501 | } 1502 | } 1503 | 1504 | // 还要尝试去获取一下接口的返回码哦 1505 | $returnUnpack = Utils::getUnpackMethods($returnInfo['type']); 1506 | $valueName = $returnInfo['valueName']; 1507 | 1508 | if ($returnInfo['type'] !== 'void') { 1509 | if (Utils::isVector($returnInfo['type']) || Utils::isMap($returnInfo['type'])) { 1510 | $bodyMiddle .= $this->tripleTab.'return TUPAPIWrapper::'.$returnUnpack.'("",0,' 1511 | .$this->getExtType($returnInfo['wholeType'], $valueName).',$sBuffer,$this->_iVersion);'.$this->doubleReturn. 1512 | $this->doubleTab.'}'.$this->returnSymbol; 1513 | } elseif (Utils::isStruct($returnInfo['type'], $this->preStructs)) { 1514 | $bodyMiddle .= $this->tripleTab."\$returnVal = new $valueName();".$this->returnSymbol; 1515 | $bodyMiddle .= $this->tripleTab.'TUPAPIWrapper::'.$returnUnpack.'("",0,$returnVal,$sBuffer,$this->_iVersion);'.$this->returnSymbol; 1516 | $bodyMiddle .= $this->tripleTab.'return $returnVal;'.$this->doubleReturn. 1517 | $this->doubleTab.'}'.$this->returnSymbol; 1518 | 1519 | if (!in_array($returnInfo['type'], $this->useStructs)) { 1520 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$returnInfo['type'].';'.$this->returnSymbol; 1521 | $this->useStructs[] = $returnInfo['type']; 1522 | } 1523 | } else { 1524 | $bodyMiddle .= $this->tripleTab.'return TUPAPIWrapper::'.$returnUnpack.'("",0,$sBuffer,$this->_iVersion);'.$this->doubleReturn. 1525 | $this->doubleTab.'}'.$this->returnSymbol; 1526 | } 1527 | } else { 1528 | $bodyMiddle .= $this->doubleTab.'}'.$this->returnSymbol; 1529 | } 1530 | 1531 | $bodyStr = $bodyPrefix.$bodyMiddle.$bodySuffix; 1532 | 1533 | return [ 1534 | 'syn' => $bodyStr, 1535 | ]; 1536 | } 1537 | } 1538 | 1539 | class StructParser 1540 | { 1541 | public $uniqueName; 1542 | public $moduleName; 1543 | public $structName; 1544 | public $state; 1545 | 1546 | // 这个结构体,可能会引用的部分,包括其他的结构体、枚举类型、常量 1547 | public $preStructs; 1548 | public $preEnums; 1549 | public $preNamespaceEnums; 1550 | public $preNamespaceStructs; 1551 | 1552 | public $returnSymbol = "\n"; 1553 | public $doubleReturn = "\n\n"; 1554 | public $tabSymbol = "\t"; 1555 | public $doubleTab = "\t\t"; 1556 | public $tripleTab = "\t\t\t"; 1557 | public $quardupleTab = "\t\t\t\t"; 1558 | 1559 | public $extraContructs = ''; 1560 | public $extraExtInit = ''; 1561 | 1562 | public $consts = ''; 1563 | public $variables = ''; 1564 | public $fields = ''; 1565 | 1566 | public $namespaceName; 1567 | 1568 | public function __construct($fp, $line, $uniqueName, $moduleName, $structName, $preStructs, $preEnums, $namespaceName, 1569 | $preNamespaceEnums, $preNamespaceStructs) 1570 | { 1571 | $this->fp = $fp; 1572 | $this->uniqueName = $uniqueName; 1573 | $this->moduleName = $moduleName; 1574 | $this->preStructs = $preStructs; 1575 | $this->preEnums = $preEnums; 1576 | $this->structName = $structName; 1577 | $this->namespaceName = $namespaceName; 1578 | 1579 | $this->consts = ''; 1580 | $this->variables = ''; 1581 | $this->fields = ''; 1582 | 1583 | $this->preNamespaceEnums = $preNamespaceEnums; 1584 | $this->preNamespaceStructs = $preNamespaceStructs; 1585 | } 1586 | 1587 | public function parse() 1588 | { 1589 | while ($this->state != 'end') { 1590 | $this->structBodyParseLine(); 1591 | } 1592 | 1593 | // 先把积累下来的三个部分处理掉 1594 | $structClassStr = $this->getStructClassHeader('\\classes'). 1595 | 'class '.$this->structName." extends \TARS_Struct {".$this->returnSymbol; 1596 | 1597 | $structClassStr .= $this->consts.$this->doubleReturn; 1598 | $structClassStr .= $this->variables.$this->doubleReturn; 1599 | $fieldsPrefix = $this->tabSymbol.'protected static $_fields = array('.$this->returnSymbol; 1600 | $fieldsSuffix = $this->tabSymbol.');'.$this->doubleReturn; 1601 | 1602 | $structClassStr .= $fieldsPrefix; 1603 | $structClassStr .= $this->fields; 1604 | $structClassStr .= $fieldsSuffix; 1605 | 1606 | // 处理最后一行 1607 | 1608 | $construct = $this->tabSymbol.'public function __construct() {'.$this->returnSymbol. 1609 | $this->doubleTab."parent::__construct('".$this->uniqueName.'_'.$this->structName."', self::\$_fields);".$this->returnSymbol 1610 | .$this->extraContructs 1611 | .$this->extraExtInit 1612 | .$this->tabSymbol.'}'.$this->returnSymbol; 1613 | 1614 | $structClassStr .= $construct.'}'.$this->returnSymbol; 1615 | 1616 | return $structClassStr; 1617 | } 1618 | 1619 | /** 1620 | * @param $startChar 1621 | * @param $lineString 1622 | * 1623 | * @return string 1624 | * 专门处理注释 1625 | */ 1626 | public function copyAnnotation($startChar, $lineString) 1627 | { 1628 | $lineString .= $startChar; 1629 | // 再读入一个字符 1630 | $nextChar = fgetc($this->fp); 1631 | // 第一种 1632 | if ($nextChar == '/') { 1633 | $lineString .= $nextChar; 1634 | while (1) { 1635 | $tmpChar = fgetc($this->fp); 1636 | if (Utils::isReturn($tmpChar)) { 1637 | $this->state = 'lineEnd'; 1638 | break; 1639 | } 1640 | $lineString .= $tmpChar; 1641 | } 1642 | 1643 | return $lineString; 1644 | } elseif ($nextChar == '*') { 1645 | $lineString .= $nextChar; 1646 | while (1) { 1647 | $tmpChar = fgetc($this->fp); 1648 | $lineString .= $tmpChar; 1649 | 1650 | if ($tmpChar === false) { 1651 | Utils::abnormalExit('error', '注释换行错误,请检查'); 1652 | } elseif (Utils::isReturn($tmpChar)) { 1653 | } elseif (($tmpChar) === '*') { 1654 | $nextnextChar = fgetc($this->fp); 1655 | if ($nextnextChar == '/') { 1656 | $lineString .= $nextnextChar; 1657 | 1658 | return $lineString; 1659 | } else { 1660 | $pos = ftell($this->fp); 1661 | fseek($this->fp, $pos - 1); 1662 | } 1663 | } 1664 | } 1665 | } 1666 | // 注释不正常 1667 | else { 1668 | Utils::abnormalExit('error', '注释换行错误,请检查'); 1669 | } 1670 | } 1671 | 1672 | /** 1673 | * @param $fp 1674 | * @param $line 1675 | * 这里必须要引入状态机了 1676 | */ 1677 | public function structBodyParseLine() 1678 | { 1679 | $validLine = false; 1680 | 1681 | $this->state = 'init'; 1682 | 1683 | $lineString = ''; 1684 | $word = ''; 1685 | $wholeType = ''; 1686 | $defaultValue = null; 1687 | 1688 | 1689 | $mapVectorState = false; 1690 | while (1) { 1691 | $char = fgetc($this->fp); 1692 | 1693 | if ($this->state == 'init') { 1694 | // 有可能是换行 1695 | if ($char == '{' || Utils::isSpace($char) || $char == '\r' 1696 | || $char == '\x0B' || $char == '\0') { 1697 | continue; 1698 | } elseif ($char == "\n") { 1699 | break; 1700 | } 1701 | // 遇到了注释会用贪婪算法全部处理完,同时填充到struct的类里面去 1702 | elseif ($char == '/') { 1703 | $this->copyAnnotation($char, $lineString); 1704 | break; 1705 | } elseif (Utils::inIdentifier($char)) { 1706 | $this->state = 'identifier'; 1707 | $word .= $char; 1708 | } 1709 | // 终止条件之1,宣告struct结束 1710 | elseif ($char == '}') { 1711 | // 需要贪心的读到"\n"为止 1712 | while (($lastChar = fgetc($this->fp)) != "\n") { 1713 | continue; 1714 | } 1715 | $this->state = 'end'; 1716 | break; 1717 | } elseif ($char == '=') { 1718 | //遇到等号,可以贪婪的向后,直到遇到;或者换行符 1719 | if (!empty($word)) { 1720 | $valueName = $word; 1721 | } 1722 | $moreChar = fgetc($this->fp); 1723 | 1724 | $defaultValue = ''; 1725 | 1726 | while ($moreChar != '\n' && $moreChar != ';' && $moreChar != '}') { 1727 | $defaultValue .= $moreChar; 1728 | 1729 | $moreChar = fgetc($this->fp); 1730 | } 1731 | //if(empty($defaultValue)) { 1732 | // Utils::abnormalExit('error','结构体'.$this->structName.'内默认值格式错误,请更正tars'); 1733 | //} 1734 | 1735 | if ($moreChar == '}') { 1736 | // 需要贪心的读到"\n"为止 1737 | while (($lastChar = fgetc($this->fp)) != "\n") { 1738 | continue; 1739 | } 1740 | $this->state = 'end'; 1741 | } else { 1742 | $this->state = 'init'; 1743 | } 1744 | } else { 1745 | //echo "char:".var_export($char,true); 1746 | //Utils::abnormalExit('error','结构体'.$this->structName.'内格式错误,请更正tars'); 1747 | continue; 1748 | } 1749 | } elseif ($this->state == 'identifier') { 1750 | $validLine = true; 1751 | // 如果遇到了space,需要检查是不是在map或vector的类型中,如果当前积累的word并不合法 1752 | // 并且又不是处在vector或map的前置状态下的话,那么就是出错了 1753 | if (Utils::isSpace($char)) { 1754 | if (Utils::isTag($word)) { 1755 | $tag = $word; 1756 | $this->state = 'init'; 1757 | $word = ''; 1758 | } elseif (Utils::isRequireType($word)) { 1759 | $requireType = $word; 1760 | $this->state = 'init'; 1761 | $word = ''; 1762 | } elseif ($word == 'unsigned') { 1763 | $word = $word.' '; 1764 | continue; 1765 | } elseif (Utils::isBasicType($word)) { 1766 | $type = $word; 1767 | $this->state = 'init'; 1768 | $word = ''; 1769 | } elseif (Utils::isStruct($word, $this->preStructs)) { 1770 | $type = $word; 1771 | $this->state = 'init'; 1772 | $word = ''; 1773 | } elseif (Utils::isEnum($word, $this->preEnums)) { 1774 | $type = 'int'; 1775 | $this->state = 'init'; 1776 | $word = ''; 1777 | } 1778 | // 增加对namespace的支持 1779 | elseif (in_array($word, $this->preNamespaceStructs)) { 1780 | $type = explode('::', $word); 1781 | $type = $type[1]; 1782 | $this->state = 'init'; 1783 | $word = ''; 1784 | } 1785 | // 增加对namespace的支持 1786 | elseif (in_array($word, $this->preNamespaceEnums)) { 1787 | $type = 'int'; 1788 | $this->state = 'init'; 1789 | $word = ''; 1790 | } elseif ($word == 'unsigned') { 1791 | $word = $word.' '; 1792 | continue; 1793 | } else { 1794 | // 读到了vector和map中间的空格,还没读完 1795 | if ($mapVectorState) { 1796 | continue; 1797 | } 1798 | // 否则剩余的部分应该就是值和默认值 1799 | else { 1800 | if (!empty($word)) { 1801 | $valueName = $word; 1802 | } 1803 | $this->state = 'init'; 1804 | $word = ''; 1805 | } 1806 | } 1807 | } 1808 | // 标志着map和vector的开始,不等到'>'的结束不罢休 1809 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 1810 | elseif ($char == '<') { 1811 | // 贪婪的向后,直到找出所有的'>' 1812 | $type = $word; 1813 | // 还会有一个wholeType,表示完整的部分 1814 | $mapVectorStack = []; 1815 | $wholeType = $type; 1816 | $wholeType .= '<'; 1817 | array_push($mapVectorStack, '<'); 1818 | while (!empty($mapVectorStack)) { 1819 | $moreChar = fgetc($this->fp); 1820 | $wholeType .= $moreChar; 1821 | if ($moreChar == '<') { 1822 | array_push($mapVectorStack, '<'); 1823 | } elseif ($moreChar == '>') { 1824 | array_pop($mapVectorStack); 1825 | } 1826 | } 1827 | 1828 | $this->state = 'init'; 1829 | $word = ''; 1830 | } elseif ($char == '=') { 1831 | //遇到等号,可以贪婪的向后,直到遇到;或者换行符 1832 | if (!empty($word)) { 1833 | $valueName = $word; 1834 | } 1835 | $moreChar = fgetc($this->fp); 1836 | 1837 | $defaultValue = ''; 1838 | 1839 | while ($moreChar != '\n' && $moreChar != ';' && $moreChar != '}') { 1840 | $defaultValue .= $moreChar; 1841 | 1842 | $moreChar = fgetc($this->fp); 1843 | } 1844 | //if(empty($defaultValue)) { 1845 | // Utils::abnormalExit('error','结构体'.$this->structName.'内默认值格式错误,请更正tars'); 1846 | //} 1847 | 1848 | if ($moreChar == '}') { 1849 | // 需要贪心的读到"\n"为止 1850 | while (($lastChar = fgetc($this->fp)) != "\n") { 1851 | continue; 1852 | } 1853 | $this->state = 'end'; 1854 | } else { 1855 | $this->state = 'init'; 1856 | } 1857 | } elseif ($char == ';') { 1858 | if (!empty($word)) { 1859 | $valueName = $word; 1860 | } 1861 | continue; 1862 | } 1863 | // 终止条件之2,同样宣告struct结束 1864 | elseif ($char == '}') { 1865 | // 需要贪心的读到"\n"为止 1866 | while (($lastChar = fgetc($this->fp)) != "\n") { 1867 | continue; 1868 | } 1869 | $this->state = 'end'; 1870 | } elseif ($char == '/') { 1871 | $lineString = $this->copyAnnotation($char, $lineString); 1872 | } elseif ($char == "\n") { 1873 | break; 1874 | } else { 1875 | $word .= $char; 1876 | } 1877 | } elseif ($this->state == 'lineEnd') { 1878 | if ($char == '}') { 1879 | // 需要贪心的读到"\n"为止 1880 | while (($lastChar = fgetc($this->fp)) != "\n") { 1881 | continue; 1882 | } 1883 | $this->state = 'end'; 1884 | } 1885 | break; 1886 | } elseif ($this->state == 'end') { 1887 | break; 1888 | } 1889 | } 1890 | 1891 | if (!$validLine) { 1892 | return; 1893 | } 1894 | 1895 | // 完成了这一行的词法解析,需要输出如下的字段 1896 | // echo "RAW tag:".$tag." requireType:".$requireType." type:".$type. 1897 | // " valueName:".$valueName. " wholeType:".$wholeType. 1898 | // " defaultValue:".$defaultValue." lineString:".$lineString."\n\n"; 1899 | 1900 | if (!isset($tag) || empty($requireType) || empty($type) || empty($valueName)) { 1901 | Utils::abnormalExit('error', '结构体'.$this->structName.'内格式错误,请更正tars'); 1902 | } elseif ($type == 'map' && empty($wholeType)) { 1903 | Utils::abnormalExit('error', '结构体'.$this->structName.'内map格式错误,请更正tars'); 1904 | } elseif ($type == 'vector' && empty($wholeType)) { 1905 | Utils::abnormalExit('error', '结构体'.$this->structName.'内vector格式错误,请更正tars'); 1906 | } else { 1907 | $this->writeStructLine($tag, $requireType, $type, $valueName, $wholeType, $defaultValue); 1908 | } 1909 | } 1910 | 1911 | /** 1912 | * @param $wholeType 1913 | * 通过完整的类型获取vector的扩展类型 1914 | * vector => new \TARS_VECTOR(new CateObj()) 1915 | * vector => new \TARS_VECTOR(\TARS::STRING) 1916 | * vector> => new \TARS_VECTOR(new \TARS_MAP(\TARS_MAP,new CateObj())) 1917 | */ 1918 | public function getExtType($wholeType, $valueName) 1919 | { 1920 | $state = 'init'; 1921 | $word = ''; 1922 | $extType = ''; 1923 | 1924 | for ($i = 0; $i < strlen($wholeType); ++$i) { 1925 | $char = $wholeType[$i]; 1926 | if ($state == 'init') { 1927 | // 如果遇到了空格 1928 | if (Utils::isSpace($char)) { 1929 | continue; 1930 | } 1931 | // 回车是停止符号 1932 | elseif (Utils::inIdentifier($char)) { 1933 | $state = 'indentifier'; 1934 | $word .= $char; 1935 | } elseif (Utils::isReturn($char)) { 1936 | break; 1937 | } elseif ($char == '>') { 1938 | $extType .= ')'; 1939 | continue; 1940 | } 1941 | } elseif ($state == 'indentifier') { 1942 | if ($char == '<') { 1943 | // 替换word,替换< 恢复初始状态 1944 | $tmp = $this->VecMapReplace($word); 1945 | $extType .= $tmp; 1946 | $extType .= '('; 1947 | $word = ''; 1948 | $state = 'init'; 1949 | } elseif ($char == '>') { 1950 | // 替换word,替换> 恢复初始状态 1951 | // 替换word,替换< 恢复初始状态 1952 | $tmp = $this->VecMapReplace($word); 1953 | $extType .= $tmp; 1954 | $extType .= ')'; 1955 | $word = ''; 1956 | $state = 'init'; 1957 | } elseif ($char == ',') { 1958 | // 替换word,替换, 恢复初始状态 1959 | // 替换word,替换< 恢复初始状态 1960 | $tmp = $this->VecMapReplace($word); 1961 | $extType .= $tmp; 1962 | $extType .= ','; 1963 | $word = ''; 1964 | $state = 'init'; 1965 | } else { 1966 | $word .= $char; 1967 | continue; 1968 | } 1969 | } 1970 | } 1971 | 1972 | return $extType; 1973 | } 1974 | 1975 | public function VecMapReplace($word) 1976 | { 1977 | $word = trim($word); 1978 | 1979 | if (Utils::isEnum($word, $this->preEnums)) { 1980 | $word = 'int'; 1981 | } 1982 | 1983 | // 遍历所有的类型 1984 | foreach (Utils::$wholeTypeMap as $key => $value) { 1985 | $word = preg_replace('/\b'.$key.'\b/', $value, $word); 1986 | } 1987 | 1988 | if (Utils::isStruct($word, $this->preStructs)) { 1989 | $word = 'new '.$word.'()'; 1990 | } 1991 | 1992 | return $word; 1993 | } 1994 | 1995 | /** 1996 | * @param $tag 1997 | * @param $requireType 1998 | * @param $type 1999 | * @param $name 2000 | * @param $wholeType 2001 | * @param $defaultValue 2002 | */ 2003 | public function writeStructLine($tag, $requireType, $type, $valueName, $wholeType, $defaultValue) 2004 | { 2005 | if ($requireType === 'require') { 2006 | $requireFlag = 'true'; 2007 | } else { 2008 | $requireFlag = 'false'; 2009 | } 2010 | 2011 | $this->consts .= $this->tabSymbol.'const '.strtoupper($valueName).' = '.$tag.';'.$this->returnSymbol; 2012 | if (!empty($defaultValue)) { 2013 | $this->variables .= $this->tabSymbol.'public $'.$valueName.'='.$defaultValue.';'.' '.$this->returnSymbol; 2014 | } else { 2015 | $this->variables .= $this->tabSymbol.'public $'.$valueName.';'.' '.$this->returnSymbol; 2016 | } 2017 | 2018 | // 基本类型,直接替换 2019 | if (Utils::isBasicType($type)) { 2020 | $this->fields .= $this->doubleTab.'self::'.strtoupper($valueName).' => array('.$this->returnSymbol. 2021 | $this->tripleTab."'name'=>'".$valueName."',".$this->returnSymbol. 2022 | $this->tripleTab."'required'=>".$requireFlag.','.$this->returnSymbol. 2023 | $this->tripleTab."'type'=>".Utils::getRealType($type).','.$this->returnSymbol. 2024 | $this->tripleTab.'),'.$this->returnSymbol; 2025 | } elseif (Utils::isStruct($type, $this->preStructs)) { 2026 | $this->fields .= $this->doubleTab.'self::'.strtoupper($valueName).' => array('.$this->returnSymbol. 2027 | $this->tripleTab."'name'=>'".$valueName."',".$this->returnSymbol. 2028 | $this->tripleTab."'required'=>".$requireFlag.','.$this->returnSymbol. 2029 | $this->tripleTab."'type'=>".Utils::getRealType($type).','.$this->returnSymbol. 2030 | $this->tripleTab.'),'.$this->returnSymbol; 2031 | $this->extraContructs .= $this->doubleTab."\$this->$valueName = new $type();".$this->returnSymbol; 2032 | } elseif (Utils::isVector($type) || Utils::isMap($type)) { 2033 | $extType = $this->getExtType($wholeType, $valueName); 2034 | $this->extraExtInit .= $this->doubleTab.'$this->'.$valueName.' = '.$extType.';'.$this->returnSymbol; 2035 | 2036 | $this->fields .= $this->doubleTab.'self::'.strtoupper($valueName).' => array('.$this->returnSymbol. 2037 | $this->tripleTab."'name'=>'".$valueName."',".$this->returnSymbol. 2038 | $this->tripleTab."'required'=>".$requireFlag.','.$this->returnSymbol. 2039 | $this->tripleTab."'type'=>".Utils::getRealType($type).','.$this->returnSymbol. 2040 | $this->tripleTab.'),'.$this->returnSymbol; 2041 | } else { 2042 | Utils::abnormalExit('error', '结构体struct'.$this->structName.'内类型有误,请更正tars'); 2043 | } 2044 | } 2045 | 2046 | public function getStructClassHeader($prefix = 'getFileHea') 2047 | { 2048 | return "namespaceName.$prefix.';'. 2049 | $this->doubleReturn; 2050 | } 2051 | } 2052 | 2053 | class ServantParser 2054 | { 2055 | public $namespaceName; 2056 | public $moduleName; 2057 | public $interfaceName; 2058 | 2059 | public $state; 2060 | 2061 | // 这个结构体,可能会引用的部分,包括其他的结构体、枚举类型、常量 2062 | public $useStructs = []; 2063 | public $extraUse; 2064 | public $preStructs; 2065 | public $preEnums; 2066 | 2067 | public $preNamespaceEnums = []; 2068 | public $preNamespaceStructs = []; 2069 | 2070 | public $firstLine; 2071 | 2072 | public $returnSymbol = "\n"; 2073 | public $doubleReturn = "\n\n"; 2074 | public $tabSymbol = "\t"; 2075 | public $doubleTab = "\t\t"; 2076 | public $tripleTab = "\t\t\t"; 2077 | public $quardupleTab = "\t\t\t\t"; 2078 | 2079 | public $extraContructs = ''; 2080 | public $extraExtType = ''; 2081 | public $extraExtInit = ''; 2082 | 2083 | public $consts = ''; 2084 | public $variables = ''; 2085 | public $fields = ''; 2086 | 2087 | public $funcSet = ''; 2088 | 2089 | public $servantName; 2090 | 2091 | public function __construct($fp, $line, $namespaceName, $moduleName, 2092 | $interfaceName, $preStructs, 2093 | $preEnums, $servantName, $preNamespaceEnums, $preNamespaceStructs) 2094 | { 2095 | $this->fp = $fp; 2096 | $this->firstLine = $line; 2097 | $this->namespaceName = $namespaceName; 2098 | $this->moduleName = $moduleName; 2099 | $this->preStructs = $preStructs; 2100 | $this->preEnums = $preEnums; 2101 | $this->interfaceName = $interfaceName; 2102 | $this->servantName = $servantName; 2103 | 2104 | $this->extraUse = ''; 2105 | $this->useStructs = []; 2106 | 2107 | $this->preNamespaceEnums = $preNamespaceEnums; 2108 | $this->preNamespaceStructs = $preNamespaceStructs; 2109 | } 2110 | 2111 | public function isEnum($word) 2112 | { 2113 | return in_array($word, $this->preEnums); 2114 | } 2115 | 2116 | public function isStruct($word) 2117 | { 2118 | return in_array($word, $this->preStructs); 2119 | } 2120 | 2121 | public function getFileHeader($prefix = '') 2122 | { 2123 | return "namespaceName.$prefix.';'. 2124 | $this->doubleReturn; 2125 | } 2126 | 2127 | public function parse() 2128 | { 2129 | while ($this->state != 'end') { 2130 | $this->InterfaceFuncParseLine(); 2131 | } 2132 | 2133 | // todo serverName+servant 2134 | $interfaceClass = $this->getFileHeader('').$this->extraUse.'interface '.$this->interfaceName.' {'.$this->returnSymbol; 2135 | 2136 | $interfaceClass .= $this->funcSet; 2137 | 2138 | $interfaceClass .= '}'.$this->doubleReturn; 2139 | 2140 | return $interfaceClass; 2141 | } 2142 | 2143 | /** 2144 | * @param $startChar 2145 | * @param $lineString 2146 | * 2147 | * @return string 2148 | * 专门处理注释 2149 | */ 2150 | public function copyAnnotation() 2151 | { 2152 | // 再读入一个字符 2153 | $nextChar = fgetc($this->fp); 2154 | // 第一种 2155 | if ($nextChar == '/') { 2156 | while (1) { 2157 | $tmpChar = fgetc($this->fp); 2158 | if (Utils::isReturn($tmpChar)) { 2159 | $this->state = 'lineEnd'; 2160 | break; 2161 | } 2162 | } 2163 | 2164 | return; 2165 | } elseif ($nextChar == '*') { 2166 | while (1) { 2167 | $tmpChar = fgetc($this->fp); 2168 | 2169 | if ($tmpChar === false) { 2170 | Utils::abnormalExit('error', $this->interfaceName.'注释换行错误,请检查'); 2171 | } elseif (Utils::isReturn($tmpChar)) { 2172 | } elseif (($tmpChar) === '*') { 2173 | $nextnextChar = fgetc($this->fp); 2174 | if ($nextnextChar == '/') { 2175 | return; 2176 | } else { 2177 | $pos = ftell($this->fp); 2178 | fseek($this->fp, $pos - 1); 2179 | } 2180 | } 2181 | } 2182 | } 2183 | // 注释不正常 2184 | else { 2185 | Utils::abnormalExit('error', $this->interfaceName.'注释换行错误,请检查'); 2186 | } 2187 | } 2188 | 2189 | /** 2190 | * @param $fp 2191 | * @param $line 2192 | * 这里必须要引入状态机了 2193 | * 这里并不一定要一个line呀,应该找)作为结束符 2194 | */ 2195 | public function InterfaceFuncParseLine() 2196 | { 2197 | $line = ''; 2198 | $this->state = 'init'; 2199 | while (1) { 2200 | $char = fgetc($this->fp); 2201 | 2202 | if ($this->state == 'init') { 2203 | // 有可能是换行 2204 | if ($char == '{' || Utils::isReturn($char)) { 2205 | continue; 2206 | } 2207 | // 遇到了注释会用贪婪算法全部处理完,同时填充到struct的类里面去 2208 | elseif ($char == '/') { 2209 | $this->copyAnnotation(); 2210 | break; 2211 | } elseif (Utils::inIdentifier($char)) { 2212 | $this->state = 'identifier'; 2213 | $line .= $char; 2214 | } 2215 | // 终止条件之1,宣告struct结束 2216 | elseif ($char == '}') { 2217 | // 需要贪心的读到"\n"为止 2218 | while (($lastChar = fgetc($this->fp)) != "\n") { 2219 | continue; 2220 | } 2221 | $this->state = 'end'; 2222 | break; 2223 | } 2224 | } elseif ($this->state == 'identifier') { 2225 | if ($char == '/') { 2226 | $this->copyAnnotation(); 2227 | } elseif ($char == ';') { 2228 | $line .= $char; 2229 | break; 2230 | } 2231 | // 终止条件之2,同样宣告interface结束 2232 | elseif ($char == '}') { 2233 | // 需要贪心的读到"\n"为止 2234 | while (($lastChar = fgetc($this->fp)) != "\n") { 2235 | continue; 2236 | } 2237 | $this->state = 'end'; 2238 | } elseif (Utils::isReturn($char)) { 2239 | continue; 2240 | } elseif ($char == ')') { 2241 | $line .= $char; 2242 | // 需要贪心的读到"\n"为止 2243 | while (($lastChar = fgetc($this->fp)) != "\n") { 2244 | continue; 2245 | } 2246 | $this->state = 'lineEnd'; 2247 | } else { 2248 | $line .= $char; 2249 | } 2250 | } elseif ($this->state == 'lineEnd') { 2251 | if ($char == '}') { 2252 | // 需要贪心的读到"\n"为止 2253 | while (($lastChar = fgetc($this->fp)) != "\n") { 2254 | continue; 2255 | } 2256 | $this->state = 'end'; 2257 | } 2258 | break; 2259 | } elseif ($this->state == 'end') { 2260 | break; 2261 | } 2262 | } 2263 | 2264 | if (empty($line)) { 2265 | return; 2266 | } 2267 | 2268 | $line = trim($line); 2269 | 2270 | // 如果空行,或者是注释,或者是大括号就直接略过 2271 | if (!trim($line) || trim($line)[0] === '/' || trim($line)[0] === '*' || trim($line) === '{') { 2272 | return; 2273 | } 2274 | 2275 | $endFlag = strpos($line, '};'); 2276 | if ($endFlag !== false) { 2277 | $this->state = 'end'; 2278 | 2279 | return; 2280 | } 2281 | 2282 | $endFlag = strpos($line, '}'); 2283 | if ($endFlag !== false) { 2284 | $this->state = 'end'; 2285 | 2286 | return; 2287 | } 2288 | 2289 | // 有必要先分成三个部分,返回类型、接口名、参数列表 todo 2290 | $tokens = preg_split('/\(/', $line, 2); 2291 | $mix = trim($tokens[0]); 2292 | $rest = $tokens[1]; 2293 | 2294 | $pices = preg_split('/\s+/', $mix); 2295 | 2296 | $funcName = $pices[count($pices) - 1]; 2297 | 2298 | $returnType = implode('', array_slice($pices, 0, count($pices) - 1)); 2299 | 2300 | $state = 'init'; 2301 | $word = ''; 2302 | 2303 | $params = []; 2304 | 2305 | for ($i = 0; $i < strlen($rest); ++$i) { 2306 | $char = $rest[$i]; 2307 | 2308 | if ($state == 'init') { 2309 | // 有可能是换行 2310 | if ($char == '(' || Utils::isSpace($char)) { 2311 | continue; 2312 | } elseif (Utils::isReturn($char)) { 2313 | break; 2314 | } elseif (Utils::inIdentifier($char)) { 2315 | $state = 'identifier'; 2316 | $word .= $char; 2317 | } 2318 | // 终止条件之1,宣告interface结束 2319 | elseif ($char == ')') { 2320 | break; 2321 | } else { 2322 | Utils::abnormalExit('error', 'Interface'.$this->interfaceName.'内格式错误,请更正tars in line:'.__LINE__); 2323 | } 2324 | } elseif ($state == 'identifier') { 2325 | if ($char == ',') { 2326 | $params[] = $word; 2327 | $state = 'init'; 2328 | $word = ''; 2329 | continue; 2330 | } 2331 | // 标志着map和vector的开始,不等到'>'的结束不罢休 2332 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 2333 | elseif ($char == '<') { 2334 | $mapVectorStack = []; 2335 | $word .= $char; 2336 | array_push($mapVectorStack, '<'); 2337 | while (!empty($mapVectorStack)) { 2338 | $moreChar = $rest[$i + 1]; 2339 | $word .= $moreChar; 2340 | if ($moreChar == '<') { 2341 | array_push($mapVectorStack, '<'); 2342 | } elseif ($moreChar == '>') { 2343 | array_pop($mapVectorStack); 2344 | } 2345 | ++$i; 2346 | } 2347 | continue; 2348 | } elseif ($char == ')') { 2349 | $params[] = $word; 2350 | break; 2351 | } elseif ($char == ';') { 2352 | continue; 2353 | } 2354 | // 终止条件之2,同样宣告struct结束 2355 | elseif ($char == '}') { 2356 | $state = 'end'; 2357 | } elseif (Utils::isReturn($char)) { 2358 | break; 2359 | } else { 2360 | $word .= $char; 2361 | } 2362 | } elseif ($state == 'lineEnd') { 2363 | break; 2364 | } elseif ($state == 'end') { 2365 | break; 2366 | } 2367 | } 2368 | 2369 | $this->writeInterfaceLine($returnType, $funcName, $params); 2370 | } 2371 | 2372 | /** 2373 | * @param $wholeType 2374 | * 通过完整的类型获取vector的扩展类型 2375 | */ 2376 | public function getExtType($wholeType) 2377 | { 2378 | $state = 'init'; 2379 | $word = ''; 2380 | $extType = ''; 2381 | 2382 | for ($i = 0; $i < strlen($wholeType); ++$i) { 2383 | $char = $wholeType[$i]; 2384 | if ($state == 'init') { 2385 | // 如果遇到了空格 2386 | if (Utils::isSpace($char)) { 2387 | continue; 2388 | } 2389 | // 回车是停止符号 2390 | elseif (Utils::inIdentifier($char)) { 2391 | $state = 'indentifier'; 2392 | $word .= $char; 2393 | } elseif (Utils::isReturn($char)) { 2394 | break; 2395 | } elseif ($char == '>') { 2396 | $extType .= ')'; 2397 | continue; 2398 | } 2399 | } elseif ($state == 'indentifier') { 2400 | if ($char == '<') { 2401 | // 替换word,替换< 恢复初始状态 2402 | $tmp = $this->VecMapReplace($word); 2403 | $extType .= $tmp; 2404 | $extType .= '('; 2405 | $word = ''; 2406 | $state = 'init'; 2407 | } elseif ($char == '>') { 2408 | // 替换word,替换> 恢复初始状态 2409 | // 替换word,替换< 恢复初始状态 2410 | $tmp = $this->VecMapReplace($word); 2411 | $extType .= $tmp; 2412 | $extType .= ')'; 2413 | $word = ''; 2414 | $state = 'init'; 2415 | } elseif ($char == ',') { 2416 | // 替换word,替换, 恢复初始状态 2417 | // 替换word,替换< 恢复初始状态 2418 | $tmp = $this->VecMapReplace($word); 2419 | $extType .= $tmp; 2420 | $extType .= ','; 2421 | $word = ''; 2422 | $state = 'init'; 2423 | } else { 2424 | $word .= $char; 2425 | continue; 2426 | } 2427 | } 2428 | } 2429 | 2430 | return $extType; 2431 | } 2432 | 2433 | public function VecMapReplace($word) 2434 | { 2435 | $word = trim($word); 2436 | // 遍历所有的类型 2437 | foreach (Utils::$wholeTypeMap as $key => $value) { 2438 | if ($this->isStruct($word)) { 2439 | $word = '\\'.$this->namespaceName.'\\classes\\'.$word; 2440 | break; 2441 | } elseif (in_array($word, $this->preNamespaceStructs)) { 2442 | $words = explode('::', $word); 2443 | $word = $words[1]; 2444 | if (!in_array($word, $this->useStructs)) { 2445 | $this->useStructs[] = $word; 2446 | } 2447 | $word = '\\'.$this->namespaceName.'\\classes\\'.$word; 2448 | break; 2449 | } elseif (in_array($word, $this->preEnums)) { 2450 | $word = 'int'; 2451 | } else { 2452 | $word = preg_replace('/\b'.$key.'\b/', $value, $word); 2453 | } 2454 | } 2455 | 2456 | $word = trim($word, 'new '); 2457 | 2458 | return $word; 2459 | } 2460 | 2461 | public function paramParser($params) 2462 | { 2463 | 2464 | // 输入和输出的参数全部捋一遍 2465 | $inParams = []; 2466 | $outParams = []; 2467 | foreach ($params as $param) { 2468 | $state = 'init'; 2469 | $word = ''; 2470 | $wholeType = ''; 2471 | $paramType = 'in'; 2472 | $type = ''; 2473 | $mapVectorState = false; 2474 | 2475 | for ($i = 0; $i < strlen($param); ++$i) { 2476 | $char = $param[$i]; 2477 | if ($state == 'init') { 2478 | // 有可能是换行 2479 | if (Utils::isSpace($char)) { 2480 | continue; 2481 | } elseif (Utils::isReturn($char)) { 2482 | break; 2483 | } elseif (Utils::inIdentifier($char)) { 2484 | $state = 'identifier'; 2485 | $word .= $char; 2486 | } else { 2487 | Utils::abnormalExit('error', 'Interface内格式错误,请更正tars in line:'.__LINE__); 2488 | } 2489 | } elseif ($state == 'identifier') { 2490 | // 如果遇到了space,需要检查是不是在map或vector的类型中,如果当前积累的word并不合法 2491 | // 并且又不是处在vector或map的前置状态下的话,那么就是出错了 2492 | if (Utils::isSpace($char)) { 2493 | if ($word == 'out') { 2494 | $paramType = $word; 2495 | $state = 'init'; 2496 | $word = ''; 2497 | } elseif (Utils::isBasicType($word)) { 2498 | $type = $word; 2499 | $state = 'init'; 2500 | $word = ''; 2501 | } elseif ($this->isStruct($word)) { 2502 | 2503 | // 同时要把它增加到本Interface的依赖中 2504 | if (!in_array($word, $this->useStructs)) { 2505 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 2506 | $this->useStructs[] = $word; 2507 | } 2508 | 2509 | $type = $word; 2510 | $state = 'init'; 2511 | $word = ''; 2512 | } elseif ($this->isEnum($word)) { 2513 | $type = 'int'; 2514 | $state = 'init'; 2515 | $word = ''; 2516 | } elseif (in_array($word, $this->preNamespaceStructs)) { 2517 | $word = explode('::', $word); 2518 | $word = $word[1]; 2519 | // 同时要把它增加到本Interface的依赖中 2520 | if (!in_array($word, $this->useStructs)) { 2521 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 2522 | $this->useStructs[] = $word; 2523 | } 2524 | 2525 | $type = $word; 2526 | $state = 'init'; 2527 | $word = ''; 2528 | } elseif (in_array($word, $this->preNamespaceEnums)) { 2529 | $type = 'int'; 2530 | $state = 'init'; 2531 | $word = ''; 2532 | } elseif (Utils::isMap($word)) { 2533 | $mapVectorState = true; 2534 | } elseif (Utils::isVector($word)) { 2535 | $mapVectorState = true; 2536 | } else { 2537 | // 读到了vector和map中间的空格,还没读完 2538 | if ($mapVectorState) { 2539 | continue; 2540 | } 2541 | // 否则剩余的部分应该就是值和默认值 2542 | else { 2543 | if (!empty($word)) { 2544 | $valueName = $word; 2545 | } 2546 | $state = 'init'; 2547 | $word = ''; 2548 | } 2549 | } 2550 | } 2551 | // 标志着map和vector的开始,不等到'>'的结束不罢休 2552 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 2553 | elseif ($char == '<') { 2554 | // 贪婪的向后,直到找出所有的'>' 2555 | $type = $word; 2556 | // 还会有一个wholeType,表示完整的部分 2557 | $mapVectorStack = []; 2558 | $wholeType = $type; 2559 | $wholeType .= '<'; 2560 | array_push($mapVectorStack, '<'); 2561 | while (!empty($mapVectorStack)) { 2562 | $moreChar = $param[$i + 1]; 2563 | $wholeType .= $moreChar; 2564 | if ($moreChar == '<') { 2565 | array_push($mapVectorStack, '<'); 2566 | } elseif ($moreChar == '>') { 2567 | array_pop($mapVectorStack); 2568 | } 2569 | ++$i; 2570 | } 2571 | 2572 | $state = 'init'; 2573 | $word = ''; 2574 | } else { 2575 | $word .= $char; 2576 | } 2577 | } 2578 | } 2579 | 2580 | if (!empty($word)) { 2581 | $valueName = $word; 2582 | } 2583 | 2584 | if ($paramType == 'in') { 2585 | $inParams[] = [ 2586 | 'type' => $type, 2587 | 'wholeType' => $wholeType, 2588 | 'valueName' => $valueName, 2589 | ]; 2590 | } else { 2591 | $outParams[] = [ 2592 | 'type' => $type, 2593 | 'wholeType' => $wholeType, 2594 | 'valueName' => $valueName, 2595 | ]; 2596 | } 2597 | } 2598 | 2599 | return [ 2600 | 'in' => $inParams, 2601 | 'out' => $outParams, 2602 | ]; 2603 | } 2604 | 2605 | public function returnParser($returnType) 2606 | { 2607 | if ($this->isStruct($returnType)) { 2608 | if (!in_array($returnType, $this->useStructs)) { 2609 | $this->useStructs[] = $returnType; 2610 | } 2611 | $returnInfo = [ 2612 | 'type' => $returnType, 2613 | 'wholeType' => $returnType, 2614 | 'valueName' => $returnType, 2615 | ]; 2616 | 2617 | return $returnInfo; 2618 | } elseif ($this->isEnum($returnType)) { 2619 | $returnInfo = [ 2620 | 'type' => $returnType, 2621 | 'wholeType' => $returnType, 2622 | 'valueName' => $returnType, 2623 | ]; 2624 | 2625 | return $returnInfo; 2626 | } elseif (Utils::isBasicType($returnType)) { 2627 | $returnInfo = [ 2628 | 'type' => $returnType, 2629 | 'wholeType' => $returnType, 2630 | 'valueName' => $returnType, 2631 | ]; 2632 | 2633 | return $returnInfo; 2634 | } 2635 | 2636 | $state = 'init'; 2637 | $word = ''; 2638 | $wholeType = ''; 2639 | $type = ''; 2640 | $mapVectorState = false; 2641 | $valueName = ''; 2642 | 2643 | for ($i = 0; $i < strlen($returnType); ++$i) { 2644 | $char = $returnType[$i]; 2645 | if ($state == 'init') { 2646 | // 有可能是换行 2647 | if (Utils::isSpace($char)) { 2648 | continue; 2649 | } elseif ($char == "\n") { 2650 | break; 2651 | } elseif (Utils::inIdentifier($char)) { 2652 | $state = 'identifier'; 2653 | $word .= $char; 2654 | } else { 2655 | Utils::abnormalExit('error', 'Interface内格式错误,请更正tars'); 2656 | } 2657 | } elseif ($state == 'identifier') { 2658 | // 如果遇到了space,需要检查是不是在map或vector的类型中,如果当前积累的word并不合法 2659 | // 并且又不是处在vector或map的前置状态下的话,那么就是出错了 2660 | if (Utils::isSpace($char)) { 2661 | if (Utils::isBasicType($word)) { 2662 | $type = $word; 2663 | $state = 'init'; 2664 | $word = ''; 2665 | } elseif ($this->isStruct($word)) { 2666 | 2667 | // 同时要把它增加到本Interface的依赖中 2668 | if (!in_array($word, $this->useStructs)) { 2669 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 2670 | $this->useStructs[] = $word; 2671 | } 2672 | 2673 | $type = $word; 2674 | $state = 'init'; 2675 | $word = ''; 2676 | } elseif ($this->isEnum($word)) { 2677 | $type = 'int'; 2678 | $state = 'init'; 2679 | $word = ''; 2680 | } elseif (in_array($word, $this->preNamespaceStructs)) { 2681 | $word = explode('::', $word); 2682 | $word = $word[1]; 2683 | // 同时要把它增加到本Interface的依赖中 2684 | if (!in_array($word, $this->useStructs)) { 2685 | $this->extraUse .= 'use '.$this->namespaceName.'\\classes\\'.$word.';'.$this->returnSymbol; 2686 | $this->useStructs[] = $word; 2687 | } 2688 | 2689 | $type = $word; 2690 | $state = 'init'; 2691 | $word = ''; 2692 | } elseif (in_array($word, $this->preNamespaceEnums)) { 2693 | $type = 'int'; 2694 | $state = 'init'; 2695 | $word = ''; 2696 | } elseif (Utils::isMap($word)) { 2697 | $mapVectorState = true; 2698 | } elseif (Utils::isVector($word)) { 2699 | $mapVectorState = true; 2700 | } else { 2701 | // 读到了vector和map中间的空格,还没读完 2702 | if ($mapVectorState) { 2703 | continue; 2704 | } 2705 | // 否则剩余的部分应该就是值和默认值 2706 | else { 2707 | if (!empty($word)) { 2708 | $valueName = $word; 2709 | } 2710 | $state = 'init'; 2711 | $word = ''; 2712 | } 2713 | } 2714 | } 2715 | // 标志着map和vector的开始,不等到'>'的结束不罢休 2716 | // 这时候需要使用栈来push,然后一个个对应的pop,从而达到type的遍历 2717 | elseif ($char == '<') { 2718 | // 贪婪的向后,直到找出所有的'>' 2719 | $type = $word; 2720 | // 还会有一个wholeType,表示完整的部分 2721 | $mapVectorStack = []; 2722 | $wholeType = $type; 2723 | $wholeType .= '<'; 2724 | array_push($mapVectorStack, '<'); 2725 | while (!empty($mapVectorStack)) { 2726 | $moreChar = $returnType[$i + 1]; 2727 | $wholeType .= $moreChar; 2728 | if ($moreChar == '<') { 2729 | array_push($mapVectorStack, '<'); 2730 | } elseif ($moreChar == '>') { 2731 | array_pop($mapVectorStack); 2732 | } 2733 | ++$i; 2734 | } 2735 | 2736 | $state = 'init'; 2737 | $word = ''; 2738 | } else { 2739 | $word .= $char; 2740 | } 2741 | } 2742 | } 2743 | 2744 | $returnInfo = [ 2745 | 'type' => $type, 2746 | 'wholeType' => $wholeType, 2747 | 'valueName' => $valueName, 2748 | ]; 2749 | 2750 | return $returnInfo; 2751 | } 2752 | 2753 | /** 2754 | * @param $tag 2755 | * @param $requireType 2756 | * @param $type 2757 | * @param $name 2758 | * @param $wholeType 2759 | * @param $defaultValue 2760 | */ 2761 | public function writeInterfaceLine($returnType, $funcName, $params) 2762 | { 2763 | $result = $this->paramParser($params); 2764 | $inParams = $result['in']; 2765 | $outParams = $result['out']; 2766 | 2767 | $returnInfo = $this->returnParser($returnType); 2768 | 2769 | $funcAnnotation = $this->generateFuncAnnotation($inParams, $outParams, $returnInfo); 2770 | 2771 | // 函数定义恰恰是要放在最后面了 2772 | $funcDefinition = $this->generateFuncHeader($funcName, $inParams, $outParams); 2773 | 2774 | $this->funcSet .= $funcAnnotation.$funcDefinition; 2775 | } 2776 | 2777 | private function paramTypeMap($paramType) 2778 | { 2779 | if (Utils::isBasicType($paramType) || Utils::isMap($paramType) || Utils::isVector($paramType)) { 2780 | return ''; 2781 | } else { 2782 | return $paramType; 2783 | } 2784 | } 2785 | /** 2786 | * @param $funcName 2787 | * @param $inParams 2788 | * @param $outParams 2789 | * 2790 | * @return string 2791 | */ 2792 | public function generateFuncHeader($funcName, $inParams, $outParams) 2793 | { 2794 | $paramsStr = ''; 2795 | foreach ($inParams as $param) { 2796 | $paramPrefix = $this->paramTypeMap($param['type']); 2797 | $paramSuffix = '$'.$param['valueName']; 2798 | $paramsStr .= !empty($paramPrefix) ? $paramPrefix.' '.$paramSuffix.',' : $paramSuffix.','; 2799 | } 2800 | 2801 | foreach ($outParams as $param) { 2802 | $paramPrefix = $this->paramTypeMap($param['type']); 2803 | $paramSuffix = '&$'.$param['valueName']; 2804 | $paramsStr .= !empty($paramPrefix) ? $paramPrefix.' '.$paramSuffix.',' : $paramSuffix.','; 2805 | } 2806 | 2807 | $paramsStr = trim($paramsStr, ','); 2808 | $paramsStr .= ');'.$this->returnSymbol; 2809 | 2810 | $funcHeader = $this->tabSymbol.'public function '.$funcName.'('.$paramsStr; 2811 | 2812 | return $funcHeader; 2813 | } 2814 | 2815 | /** 2816 | * @param $funcName 2817 | * @param $inParams 2818 | * @param $outParams 2819 | * 生成函数的包体 2820 | */ 2821 | public function generateFuncAnnotation($inParams, $outParams, $returnInfo) 2822 | { 2823 | $bodyPrefix = $this->tabSymbol.'/**'.$this->returnSymbol; 2824 | 2825 | $bodyMiddle = ''; 2826 | 2827 | foreach ($inParams as $param) { 2828 | $annotation = $this->tabSymbol.' * @param '; 2829 | $type = $param['type']; 2830 | $valueName = $param['valueName']; 2831 | $wholeType = $param['wholeType']; 2832 | 2833 | // 判断如果是vector需要特别的处理 2834 | if (Utils::isVector($type)) { 2835 | $annotation .= 'vector'.' $'.$valueName.' '.$this->getExtType($wholeType); 2836 | } 2837 | 2838 | // 判断如果是map需要特别的处理 2839 | elseif (Utils::isMap($type)) { 2840 | $annotation .= 'map'.' $'.$valueName.' '.$this->getExtType($wholeType); 2841 | } 2842 | // 针对struct,需要额外的use过程 2843 | elseif ($this->isStruct($type)) { 2844 | $annotation .= 'struct'.' $'.$valueName.' \\'.$this->namespaceName.'\\classes\\'.$type; 2845 | } else { 2846 | $annotation .= $type.' $'.$valueName.' '; 2847 | } 2848 | $bodyMiddle .= $annotation.$this->returnSymbol; 2849 | } 2850 | 2851 | foreach ($outParams as $param) { 2852 | $annotation = $this->tabSymbol.' * @param '; 2853 | $type = $param['type']; 2854 | $valueName = $param['valueName']; 2855 | $wholeType = $param['wholeType']; 2856 | 2857 | if (Utils::isBasicType($type)) { 2858 | $annotation .= $type.' $'.$valueName; 2859 | } else { 2860 | // 判断如果是vector需要特别的处理 2861 | if (Utils::isVector($type)) { 2862 | $annotation .= 'vector'.' $'.$valueName.' '.$this->getExtType($wholeType); 2863 | } elseif (Utils::isMap($type)) { 2864 | $annotation .= 'map'.' $'.$valueName.' '.$this->getExtType($wholeType); 2865 | } 2866 | // 如果是struct 2867 | elseif ($this->isStruct($type)) { 2868 | $annotation .= 'struct'.' $'.$valueName.' \\'.$this->namespaceName.'\\classes\\'.$type; 2869 | } 2870 | } 2871 | 2872 | $annotation .= ' =out='.$this->returnSymbol; 2873 | $bodyMiddle .= $annotation; 2874 | } 2875 | 2876 | // 还要尝试去获取一下接口的返回码哦 2877 | $type = $returnInfo['type']; 2878 | $valueName = $returnInfo['valueName']; 2879 | $wholeType = $returnInfo['wholeType']; 2880 | 2881 | $annotation = $this->tabSymbol.' * @return '; 2882 | 2883 | if ($type !== 'void') { 2884 | if (Utils::isVector($type)) { 2885 | $annotation .= 'vector '.$this->getExtType($wholeType); 2886 | } elseif (Utils::isMap($type)) { 2887 | $annotation .= 'map '.$this->getExtType($wholeType); 2888 | } elseif ($this->isStruct($type)) { 2889 | $annotation .= 'struct \\'.$this->namespaceName.'\\classes\\'.$type; 2890 | } elseif ($this->isEnum($type)) { 2891 | $annotation .= 'int'; 2892 | } else { 2893 | $annotation .= $type; 2894 | } 2895 | } else { 2896 | $annotation .= 'void'; 2897 | } 2898 | 2899 | $bodyMiddle .= $annotation.$this->returnSymbol.$this->tabSymbol.' */'.$this->returnSymbol; 2900 | 2901 | $bodyStr = $bodyPrefix.$bodyMiddle; 2902 | 2903 | return $bodyStr; 2904 | } 2905 | } 2906 | --------------------------------------------------------------------------------