/** * Clears/Resets a field by tag number * * @throws \Exception If trying to modify an unknown field * @param int $tag * @return \StudyDrSlump\Protobuf\Message - Fluent interface */ public function _clear($tag) { $f = $this->_descriptor->getField($tag); if (!$f) { throw new \Exception('Unknown fields not supported'); } $name = $f->getName(); if (!$f->isExtension()) { $this->{$name} = $f->isRepeated() ? array() : NULL; } else { $this->_extensions[$name] = $f->isRepeated() ? array() : NULL; } return $this; }
public static function descriptor() { $class = get_called_class(); // Instantiate a new descriptor $descriptor = new Descriptor($class); $rflClass = new \ReflectionClass($class); $props = $rflClass->getProperties(); foreach ($props as $prop) { $doc = $prop->getDocComment(); if (empty($doc)) { continue; } // Format: @protobuf(tag=X, type=bool, required=true) // Extract annotation from the comment if (!preg_match('/@protobuf\\s?\\(([^\\)]+)\\)/', $doc, $m)) { continue; } // Parse params $params = explode(',', $m[1]); $params = array_filter(array_map('trim', $params)); $options = array(); foreach ($params as $param) { $parts = explode('=', $param); $parts = array_filter(array_map('trim', $parts)); $options[$parts[0]] = count($parts) < 2 ? true : $parts[1]; } // Check if we have the minimum required options if (empty($options['tag'])) { throw new \InvalidArgumentException('The tag option is required for property ' . $prop->getName()); } if (empty($options['type'])) { throw new \InvalidArgumentException('The type option is required for property ' . $prop->getName()); } // Normalize boolean values foreach (array('required', 'optional', 'repeated', 'packed') as $opt) { if (isset($options[$opt])) { $options[$opt] = filter_var($options[$opt], FILTER_VALIDATE_BOOLEAN); } } // Build a field descriptor $f = new Protobuf\Field(); $f->number = (int) $options['tag']; $f->name = $prop->getName(); // Convert type name to its numeric constant switch (strtolower($options['type'])) { case 'double': $f->type = Protobuf::TYPE_DOUBLE; break; case 'float': $f->type = Protobuf::TYPE_FLOAT; break; case 'int64': $f->type = Protobuf::TYPE_INT64; break; case 'uint64': $f->type = Protobuf::TYPE_UINT64; break; case 'int32': $f->type = Protobuf::TYPE_INT32; break; case 'fixed64': $f->type = Protobuf::TYPE_FIXED64; break; case 'fixed32': $f->type = Protobuf::TYPE_FIXED32; break; case 'bool': $f->type = Protobuf::TYPE_BOOL; break; case 'string': $f->type = Protobuf::TYPE_STRING; break; case 'message': $f->type = Protobuf::TYPE_MESSAGE; break; case 'bytes': $f->type = Protobuf::TYPE_BYTES; break; case 'uint32': $f->type = Protobuf::TYPE_UINT32; break; case 'enum': $f->type = Protobuf::TYPE_ENUM; break; case 'sfixed32': $f->type = Protobuf::TYPE_SFIXED32; break; case 'sfixed64': $f->type = Protobuf::TYPE_SFIXED64; break; case 'sint32': $f->type = Protobuf::TYPE_SINT32; break; case 'sint64': $f->type = Protobuf::TYPE_SINT64; break; default: throw new \InvalidArgumentException('Type ' . $options['type'] . ' is not recognized as valid for property ' . $prop->getName()); } // Define the rule type $f->rule = Protobuf::RULE_OPTIONAL; if (!empty($options['required'])) { $f->rule = Protobuf::RULE_REQUIRED; } if (!empty($options['repeated'])) { $f->rule = Protobuf::RULE_REPEATED; } // Check if it's flagged as packed if (isset($options['packed'])) { $f->packed = $options['packed']; } // Get the reference if (isset($options['reference'])) { $f->reference = $options['reference']; } else { if ($f->type === Protobuf::TYPE_MESSAGE || $f->type === Protobuf::TYPE_ENUM) { throw new \InvalidArgumentException('Property ' . $prop->getName() . ' requires the "reference" option'); } } if (isset($options['default'])) { $f->default = $options['default']; } // Add the field to the message descriptor $descriptor->addField($f); } return $descriptor; }