1<?php 2/* 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 * @package thrift 21 */ 22 23namespace Thrift\Base; 24 25use Thrift\Type\TType; 26 27/** 28 * Base class from which other Thrift structs extend. This is so that we can 29 * cut back on the size of the generated code which is turning out to have a 30 * nontrivial cost just to load thanks to the wondrously abysmal implementation 31 * of PHP. Note that code is intentionally duplicated in here to avoid making 32 * function calls for every field or member of a container.. 33 */ 34abstract class TBase 35{ 36 public static $tmethod = array( 37 TType::BOOL => 'Bool', 38 TType::BYTE => 'Byte', 39 TType::I16 => 'I16', 40 TType::I32 => 'I32', 41 TType::I64 => 'I64', 42 TType::DOUBLE => 'Double', 43 TType::STRING => 'String' 44 ); 45 46 abstract public function read($input); 47 48 abstract public function write($output); 49 50 public function __construct($spec = null, $vals = null) 51 { 52 if (is_array($spec) && is_array($vals)) { 53 foreach ($spec as $fid => $fspec) { 54 $var = $fspec['var']; 55 if (isset($vals[$var])) { 56 $this->$var = $vals[$var]; 57 } 58 } 59 } 60 } 61 62 public function __wakeup() 63 { 64 $this->__construct(get_object_vars($this)); 65 } 66 67 private function _readMap(&$var, $spec, $input) 68 { 69 $xfer = 0; 70 $ktype = $spec['ktype']; 71 $vtype = $spec['vtype']; 72 $kread = $vread = null; 73 if (isset(TBase::$tmethod[$ktype])) { 74 $kread = 'read' . TBase::$tmethod[$ktype]; 75 } else { 76 $kspec = $spec['key']; 77 } 78 if (isset(TBase::$tmethod[$vtype])) { 79 $vread = 'read' . TBase::$tmethod[$vtype]; 80 } else { 81 $vspec = $spec['val']; 82 } 83 $var = array(); 84 $_ktype = $_vtype = $size = 0; 85 $xfer += $input->readMapBegin($_ktype, $_vtype, $size); 86 for ($i = 0; $i < $size; ++$i) { 87 $key = $val = null; 88 if ($kread !== null) { 89 $xfer += $input->$kread($key); 90 } else { 91 switch ($ktype) { 92 case TType::STRUCT: 93 $class = $kspec['class']; 94 $key = new $class(); 95 $xfer += $key->read($input); 96 break; 97 case TType::MAP: 98 $xfer += $this->_readMap($key, $kspec, $input); 99 break; 100 case TType::LST: 101 $xfer += $this->_readList($key, $kspec, $input, false); 102 break; 103 case TType::SET: 104 $xfer += $this->_readList($key, $kspec, $input, true); 105 break; 106 } 107 } 108 if ($vread !== null) { 109 $xfer += $input->$vread($val); 110 } else { 111 switch ($vtype) { 112 case TType::STRUCT: 113 $class = $vspec['class']; 114 $val = new $class(); 115 $xfer += $val->read($input); 116 break; 117 case TType::MAP: 118 $xfer += $this->_readMap($val, $vspec, $input); 119 break; 120 case TType::LST: 121 $xfer += $this->_readList($val, $vspec, $input, false); 122 break; 123 case TType::SET: 124 $xfer += $this->_readList($val, $vspec, $input, true); 125 break; 126 } 127 } 128 $var[$key] = $val; 129 } 130 $xfer += $input->readMapEnd(); 131 132 return $xfer; 133 } 134 135 private function _readList(&$var, $spec, $input, $set = false) 136 { 137 $xfer = 0; 138 $etype = $spec['etype']; 139 $eread = $vread = null; 140 if (isset(TBase::$tmethod[$etype])) { 141 $eread = 'read' . TBase::$tmethod[$etype]; 142 } else { 143 $espec = $spec['elem']; 144 } 145 $var = array(); 146 $_etype = $size = 0; 147 if ($set) { 148 $xfer += $input->readSetBegin($_etype, $size); 149 } else { 150 $xfer += $input->readListBegin($_etype, $size); 151 } 152 for ($i = 0; $i < $size; ++$i) { 153 $elem = null; 154 if ($eread !== null) { 155 $xfer += $input->$eread($elem); 156 } else { 157 $espec = $spec['elem']; 158 switch ($etype) { 159 case TType::STRUCT: 160 $class = $espec['class']; 161 $elem = new $class(); 162 $xfer += $elem->read($input); 163 break; 164 case TType::MAP: 165 $xfer += $this->_readMap($elem, $espec, $input); 166 break; 167 case TType::LST: 168 $xfer += $this->_readList($elem, $espec, $input, false); 169 break; 170 case TType::SET: 171 $xfer += $this->_readList($elem, $espec, $input, true); 172 break; 173 } 174 } 175 if ($set) { 176 $var[$elem] = true; 177 } else { 178 $var [] = $elem; 179 } 180 } 181 if ($set) { 182 $xfer += $input->readSetEnd(); 183 } else { 184 $xfer += $input->readListEnd(); 185 } 186 187 return $xfer; 188 } 189 190 protected function _read($class, $spec, $input) 191 { 192 $xfer = 0; 193 $fname = null; 194 $ftype = 0; 195 $fid = 0; 196 $xfer += $input->readStructBegin($fname); 197 while (true) { 198 $xfer += $input->readFieldBegin($fname, $ftype, $fid); 199 if ($ftype == TType::STOP) { 200 break; 201 } 202 if (isset($spec[$fid])) { 203 $fspec = $spec[$fid]; 204 $var = $fspec['var']; 205 if ($ftype == $fspec['type']) { 206 $xfer = 0; 207 if (isset(TBase::$tmethod[$ftype])) { 208 $func = 'read' . TBase::$tmethod[$ftype]; 209 $xfer += $input->$func($this->$var); 210 } else { 211 switch ($ftype) { 212 case TType::STRUCT: 213 $class = $fspec['class']; 214 $this->$var = new $class(); 215 $xfer += $this->$var->read($input); 216 break; 217 case TType::MAP: 218 $xfer += $this->_readMap($this->$var, $fspec, $input); 219 break; 220 case TType::LST: 221 $xfer += $this->_readList($this->$var, $fspec, $input, false); 222 break; 223 case TType::SET: 224 $xfer += $this->_readList($this->$var, $fspec, $input, true); 225 break; 226 } 227 } 228 } else { 229 $xfer += $input->skip($ftype); 230 } 231 } else { 232 $xfer += $input->skip($ftype); 233 } 234 $xfer += $input->readFieldEnd(); 235 } 236 $xfer += $input->readStructEnd(); 237 238 return $xfer; 239 } 240 241 private function _writeMap($var, $spec, $output) 242 { 243 $xfer = 0; 244 $ktype = $spec['ktype']; 245 $vtype = $spec['vtype']; 246 $kwrite = $vwrite = null; 247 if (isset(TBase::$tmethod[$ktype])) { 248 $kwrite = 'write' . TBase::$tmethod[$ktype]; 249 } else { 250 $kspec = $spec['key']; 251 } 252 if (isset(TBase::$tmethod[$vtype])) { 253 $vwrite = 'write' . TBase::$tmethod[$vtype]; 254 } else { 255 $vspec = $spec['val']; 256 } 257 $xfer += $output->writeMapBegin($ktype, $vtype, count($var)); 258 foreach ($var as $key => $val) { 259 if (isset($kwrite)) { 260 $xfer += $output->$kwrite($key); 261 } else { 262 switch ($ktype) { 263 case TType::STRUCT: 264 $xfer += $key->write($output); 265 break; 266 case TType::MAP: 267 $xfer += $this->_writeMap($key, $kspec, $output); 268 break; 269 case TType::LST: 270 $xfer += $this->_writeList($key, $kspec, $output, false); 271 break; 272 case TType::SET: 273 $xfer += $this->_writeList($key, $kspec, $output, true); 274 break; 275 } 276 } 277 if (isset($vwrite)) { 278 $xfer += $output->$vwrite($val); 279 } else { 280 switch ($vtype) { 281 case TType::STRUCT: 282 $xfer += $val->write($output); 283 break; 284 case TType::MAP: 285 $xfer += $this->_writeMap($val, $vspec, $output); 286 break; 287 case TType::LST: 288 $xfer += $this->_writeList($val, $vspec, $output, false); 289 break; 290 case TType::SET: 291 $xfer += $this->_writeList($val, $vspec, $output, true); 292 break; 293 } 294 } 295 } 296 $xfer += $output->writeMapEnd(); 297 298 return $xfer; 299 } 300 301 private function _writeList($var, $spec, $output, $set = false) 302 { 303 $xfer = 0; 304 $etype = $spec['etype']; 305 $ewrite = null; 306 if (isset(TBase::$tmethod[$etype])) { 307 $ewrite = 'write' . TBase::$tmethod[$etype]; 308 } else { 309 $espec = $spec['elem']; 310 } 311 if ($set) { 312 $xfer += $output->writeSetBegin($etype, count($var)); 313 } else { 314 $xfer += $output->writeListBegin($etype, count($var)); 315 } 316 foreach ($var as $key => $val) { 317 $elem = $set ? $key : $val; 318 if (isset($ewrite)) { 319 $xfer += $output->$ewrite($elem); 320 } else { 321 switch ($etype) { 322 case TType::STRUCT: 323 $xfer += $elem->write($output); 324 break; 325 case TType::MAP: 326 $xfer += $this->_writeMap($elem, $espec, $output); 327 break; 328 case TType::LST: 329 $xfer += $this->_writeList($elem, $espec, $output, false); 330 break; 331 case TType::SET: 332 $xfer += $this->_writeList($elem, $espec, $output, true); 333 break; 334 } 335 } 336 } 337 if ($set) { 338 $xfer += $output->writeSetEnd(); 339 } else { 340 $xfer += $output->writeListEnd(); 341 } 342 343 return $xfer; 344 } 345 346 protected function _write($class, $spec, $output) 347 { 348 $xfer = 0; 349 $xfer += $output->writeStructBegin($class); 350 foreach ($spec as $fid => $fspec) { 351 $var = $fspec['var']; 352 if ($this->$var !== null) { 353 $ftype = $fspec['type']; 354 $xfer += $output->writeFieldBegin($var, $ftype, $fid); 355 if (isset(TBase::$tmethod[$ftype])) { 356 $func = 'write' . TBase::$tmethod[$ftype]; 357 $xfer += $output->$func($this->$var); 358 } else { 359 switch ($ftype) { 360 case TType::STRUCT: 361 $xfer += $this->$var->write($output); 362 break; 363 case TType::MAP: 364 $xfer += $this->_writeMap($this->$var, $fspec, $output); 365 break; 366 case TType::LST: 367 $xfer += $this->_writeList($this->$var, $fspec, $output, false); 368 break; 369 case TType::SET: 370 $xfer += $this->_writeList($this->$var, $fspec, $output, true); 371 break; 372 } 373 } 374 $xfer += $output->writeFieldEnd(); 375 } 376 } 377 $xfer += $output->writeFieldStop(); 378 $xfer += $output->writeStructEnd(); 379 380 return $xfer; 381 } 382} 383