Sabre: VObject to v4.5.0 and Xml to v3.0.0

This commit is contained in:
the-djmaze 2022-09-05 11:05:38 +02:00
parent fe20741409
commit 5a9540b9c3
24 changed files with 189 additions and 127 deletions

View file

@ -456,7 +456,7 @@ HELP
*/
protected function color($vObj)
{
fwrite($this->stdout, $this->serializeComponent($vObj));
$this->serializeComponent($vObj);
}
/**

View file

@ -28,7 +28,7 @@ class Component extends Node
/**
* A list of properties and/or sub-components.
*
* @var array
* @var array<string, Component|Property>
*/
protected $children = [];
@ -43,12 +43,12 @@ class Component extends Node
* an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
* ensure that this does not happen, set $defaults to false.
*
* @param string $name such as VCALENDAR, VEVENT
* @param bool $defaults
* @param string|null $name such as VCALENDAR, VEVENT
* @param bool $defaults
*/
public function __construct(Document $root, $name, array $children = [], $defaults = true)
{
$this->name = strtoupper($name);
$this->name = isset($name) ? strtoupper($name) : '';
$this->root = $root;
if ($defaults) {
@ -238,7 +238,7 @@ class Component extends Node
return array_filter(
$result,
function ($child) use ($group) {
return $child instanceof Property && strtoupper($child->group) === $group;
return $child instanceof Property && (null !== $child->group ? strtoupper($child->group) : '') === $group;
}
);
}
@ -249,7 +249,7 @@ class Component extends Node
$result = [];
foreach ($this->children as $childGroup) {
foreach ($childGroup as $child) {
if ($child instanceof Property && $child->group && strtoupper($child->group) === $group) {
if ($child instanceof Property && (null !== $child->group ? strtoupper($child->group) : '') === $group) {
$result[] = $child;
}
}

View file

@ -52,11 +52,12 @@ class Parameter extends Node
*/
public function __construct(Document $root, $name, $value = null)
{
$this->name = strtoupper($name);
$this->root = $root;
if (is_null($name)) {
$this->noName = true;
$this->name = static::guessParameterNameByValue($value);
} else {
$this->name = strtoupper($name);
}
// If guessParameterNameByValue() returns an empty string

View file

@ -167,7 +167,11 @@ class MimeDir extends Parser
while (true) {
// Reading until we hit END:
$line = $this->readLine();
try {
$line = $this->readLine();
} catch (EofException $oEx) {
$line = 'END:'.$this->root->name;
}
if ('END:' === strtoupper(substr($line, 0, 4))) {
break;
}
@ -372,12 +376,22 @@ class MimeDir extends Parser
$value = $this->unescapeParam($value);
if (is_null($lastParam)) {
if ($this->options & self::OPTION_IGNORE_INVALID_LINES) {
// When the property can't be matched and the configuration
// option is set to ignore invalid lines, we ignore this line
// This can happen when servers provide faulty data as iCloud
// frequently does with X-APPLE-STRUCTURED-LOCATION
continue;
}
throw new ParseException('Invalid Mimedir file. Line starting at '.$this->startLine.' did not follow iCalendar/vCard conventions');
}
if (is_null($property['parameters'][$lastParam])) {
$property['parameters'][$lastParam] = $value;
} elseif (is_array($property['parameters'][$lastParam])) {
$property['parameters'][$lastParam][] = $value;
} elseif ($property['parameters'][$lastParam] === $value) {
// When the current value of the parameter is the same as the
// new one, then we can leave the current parameter as it is.
} else {
$property['parameters'][$lastParam] = [
$property['parameters'][$lastParam],

View file

@ -30,7 +30,7 @@ abstract class Property extends Node
*
* This is only used in vcards
*
* @var string
* @var string|null
*/
public $group;

View file

@ -136,16 +136,18 @@ class Text extends Property
}
foreach ($item as &$subItem) {
$subItem = strtr(
$subItem,
[
'\\' => '\\\\',
';' => '\;',
',' => '\,',
"\n" => '\n',
"\r" => '',
]
);
if (!is_null($subItem)) {
$subItem = strtr(
$subItem,
[
'\\' => '\\\\',
';' => '\;',
',' => '\,',
"\n" => '\n',
"\r" => '',
]
);
}
}
$item = implode(',', $item);
}

View file

@ -24,6 +24,13 @@ use Sabre\VObject\Property;
*/
class RRuleIterator implements Iterator
{
/**
* Constant denoting the upper limit on how long into the future
* we want to iterate. The value is a unix timestamp and currently
* corresponds to the datetime 9999-12-31 11:59:59 UTC.
*/
const dateUpperLimit = 253402300799;
/**
* Creates the Iterator.
*
@ -366,6 +373,12 @@ class RRuleIterator implements Iterator
// Current hour of the day
$currentHour = $this->currentDate->format('G');
if ($this->currentDate->getTimestamp() > self::dateUpperLimit) {
$this->currentDate = null;
return;
}
} while (
($this->byDay && !in_array($currentDay, $recurrenceDays)) ||
($this->byHour && !in_array($currentHour, $recurrenceHours)) ||
@ -486,7 +499,7 @@ class RRuleIterator implements Iterator
// To prevent running this forever (better: until we hit the max date of DateTimeImmutable) we simply
// stop at 9999-12-31. Looks like the year 10000 problem is not solved in php ....
if ($this->currentDate->getTimestamp() > 253402300799) {
if ($this->currentDate->getTimestamp() > self::dateUpperLimit) {
$this->currentDate = null;
return;
@ -589,11 +602,12 @@ class RRuleIterator implements Iterator
// loop through all YearDay and Days to check all the combinations
foreach ($this->byYearDay as $byYearDay) {
$date = clone $this->currentDate;
$date = $date->setDate($currentYear, 1, 1);
if ($byYearDay > 0) {
$date = $date->add(new \DateInterval('P'.$byYearDay.'D'));
$date = $date->setDate($currentYear, 1, 1);
$date = $date->add(new \DateInterval('P'.($byYearDay - 1).'D'));
} else {
$date = $date->sub(new \DateInterval('P'.abs($byYearDay).'D'));
$date = $date->setDate($currentYear, 12, 31);
$date = $date->sub(new \DateInterval('P'.abs($byYearDay + 1).'D'));
}
if ($date > $this->currentDate && in_array($date->format('N'), $dayOffsets)) {
@ -658,6 +672,14 @@ class RRuleIterator implements Iterator
(int) $currentMonth,
(int) $currentDayOfMonth
);
// To prevent running this forever (better: until we hit the max date of DateTimeImmutable) we simply
// stop at 9999-12-31. Looks like the year 10000 problem is not solved in php ....
if ($this->currentDate->getTimestamp() > self::dateUpperLimit) {
$this->currentDate = null;
return;
}
}
// If we made it here, it means we got a valid occurrence

View file

@ -140,6 +140,8 @@ class VCardConverter
$newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-KIND', 'GROUP');
break;
}
} elseif ('MEMBER' === $property->name) {
$newProperty = $output->createProperty('X-ADDRESSBOOKSERVER-MEMBER', $property->getValue());
}
} elseif (Document::VCARD40 === $targetVersion) {
// These properties were removed in vCard 4.0
@ -173,6 +175,9 @@ class VCardConverter
$newProperty = $output->createProperty('KIND', 'GROUP');
}
break;
case 'X-ADDRESSBOOKSERVER-MEMBER':
$newProperty = $output->createProperty('MEMBER', $property->getValue());
break;
case 'X-ANNIVERSARY':
$newProperty->name = 'ANNIVERSARY';
// If we already have an anniversary property with the same

View file

@ -14,5 +14,5 @@ class Version
/**
* Full version number.
*/
const VERSION = '4.4.2';
const VERSION = '4.5.0';
}

View file

@ -32,9 +32,9 @@ trait ContextStackTrait
* Values may also be a callable. In that case the function will be called
* directly.
*
* @var array
* @phpstan-var array<string, class-string|callable|object>
*/
public $elementMap = [];
public array $elementMap = [];
/**
* A contextUri pointing to the document being parsed / written.
@ -44,10 +44,8 @@ trait ContextStackTrait
* The reader and writer don't use this property, but as it's an extremely
* common use-case for parsing XML documents, it's added here as a
* convenience.
*
* @var string|null
*/
public $contextUri;
public ?string $contextUri = null;
/**
* This is a list of namespaces that you want to give default prefixes.
@ -55,9 +53,9 @@ trait ContextStackTrait
* You must make sure you create this entire list before starting to write.
* They should be registered on the root element.
*
* @var array
* @phpstan-var array<string, class-string|string|null>
*/
public $namespaceMap = [];
public array $namespaceMap = [];
/**
* This is a list of custom serializers for specific classes.
@ -75,16 +73,16 @@ trait ContextStackTrait
*
* function (Writer $writer, object $value)
*
* @var array
* @phpstan-var array<class-string, callable(Writer, object):mixed>
*/
public $classMap = [];
public array $classMap = [];
/**
* Backups of previous contexts.
*
* @var array
* @var list<mixed>
*/
protected $contextStack = [];
protected array $contextStack = [];
/**
* Create a new "context".
@ -93,7 +91,7 @@ trait ContextStackTrait
* namespaceMap. After you're done, you can restore the old data again
* with popContext.
*/
public function pushContext()
public function pushContext(): void
{
$this->contextStack[] = [
$this->elementMap,
@ -106,7 +104,7 @@ trait ContextStackTrait
/**
* Restore the previous "context".
*/
public function popContext()
public function popContext(): void
{
list(
$this->elementMap,

View file

@ -54,6 +54,8 @@ use Sabre\Xml\Reader;
*
* Attributes will be removed from the top-level elements. If elements with
* the same name appear twice in the list, only the last one will be kept.
*
* @phpstan-return array<string, mixed>
*/
function keyValue(Reader $reader, string $namespace = null): array
{
@ -143,6 +145,7 @@ function keyValue(Reader $reader, string $namespace = null): array
* ];
*
* @return string[]
* @phpstan-return list<string>
*/
function enum(Reader $reader, string $namespace = null): array
{
@ -189,9 +192,12 @@ function enum(Reader $reader, string $namespace = null): array
* This is primarily used by the mapValueObject function from the Service
* class, but it can also easily be used for more specific situations.
*
* @return object
* @template C of object
*
* @param class-string<C> $className
* @phpstan-return C
*/
function valueObject(Reader $reader, string $className, string $namespace)
function valueObject(Reader $reader, string $className, string $namespace): object
{
$valueObject = new $className();
if ($reader->isEmptyElement) {
@ -250,6 +256,8 @@ function valueObject(Reader $reader, string $className, string $namespace)
*
* $childElementName must either be a a clark-notation element name, or if no
* namespace is used, the bare element name.
*
* @phpstan-return list<mixed>
*/
function repeatingElements(Reader $reader, string $childElementName): array
{
@ -268,7 +276,7 @@ function repeatingElements(Reader $reader, string $childElementName): array
}
/**
* This deserializer helps you to deserialize structures which contain mixed content like this:.
* This deserializer helps you to deserialize structures which contain mixed content.
*
* <p>some text <extref>and a inline tag</extref>and even more text</p>
*
@ -285,6 +293,8 @@ function repeatingElements(Reader $reader, string $childElementName): array
* ]
*
* In strict XML documents you wont find this kind of markup but in html this is a quite common pattern.
*
* @return array<mixed>
*/
function mixedContent(Reader $reader): array
{

View file

@ -28,6 +28,8 @@ class Base implements Xml\Element
/**
* Constructor.
*
* @param mixed $value
*/
public function __construct($value = null)
{
@ -50,7 +52,7 @@ class Base implements Xml\Element
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Xml\Writer $writer)
public function xmlSerialize(Xml\Writer $writer): void
{
$writer->write($this->value);
}

View file

@ -23,10 +23,8 @@ class Cdata implements Xml\XmlSerializable
{
/**
* CDATA element value.
*
* @var string
*/
protected $value;
protected string $value;
/**
* Constructor.
@ -52,7 +50,7 @@ class Cdata implements Xml\XmlSerializable
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Xml\Writer $writer)
public function xmlSerialize(Xml\Writer $writer): void
{
$writer->writeCData($this->value);
}

View file

@ -40,12 +40,14 @@ class Elements implements Xml\Element
/**
* Value to serialize.
*
* @var array
* @var array<int, mixed>
*/
protected $value;
protected array $value;
/**
* Constructor.
*
* @param array<int, mixed> $value
*/
public function __construct(array $value = [])
{
@ -68,7 +70,7 @@ class Elements implements Xml\Element
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Xml\Writer $writer)
public function xmlSerialize(Xml\Writer $writer): void
{
Serializer\enum($writer, $this->value);
}
@ -91,9 +93,9 @@ class Elements implements Xml\Element
* $reader->parseSubTree() will parse the entire sub-tree, and advance to
* the next element.
*
* @return mixed
* @return string[]
*/
public static function xmlDeserialize(Xml\Reader $reader)
public static function xmlDeserialize(Xml\Reader $reader): array
{
return Deserializer\enum($reader);
}

View file

@ -40,12 +40,14 @@ class KeyValue implements Xml\Element
/**
* Value to serialize.
*
* @var array
* @var array<string, mixed>
*/
protected $value;
protected array $value;
/**
* Constructor.
*
* @param array<string, mixed> $value
*/
public function __construct(array $value = [])
{
@ -68,7 +70,7 @@ class KeyValue implements Xml\Element
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Xml\Writer $writer)
public function xmlSerialize(Xml\Writer $writer): void
{
$writer->write($this->value);
}
@ -91,9 +93,9 @@ class KeyValue implements Xml\Element
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
* the next element.
*
* @return mixed
* @return array<string, mixed>
*/
public static function xmlDeserialize(Xml\Reader $reader)
public static function xmlDeserialize(Xml\Reader $reader): array
{
return Deserializer\keyValue($reader);
}

View file

@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Sabre\Xml\Element;
use function Sabre\Uri\resolve;
use Sabre\Xml;
/**
@ -26,17 +28,13 @@ class Uri implements Xml\Element
{
/**
* Uri element value.
*
* @var string
*/
protected $value;
protected string $value;
/**
* Constructor.
*
* @param string $value
*/
public function __construct($value)
public function __construct(string $value)
{
$this->value = $value;
}
@ -57,10 +55,10 @@ class Uri implements Xml\Element
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Xml\Writer $writer)
public function xmlSerialize(Xml\Writer $writer): void
{
$writer->text(
\Sabre\Uri\resolve(
resolve(
$writer->contextUri,
$this->value
)
@ -84,13 +82,11 @@ class Uri implements Xml\Element
*
* $reader->parseSubTree() will parse the entire sub-tree, and advance to
* the next element.
*
* @return mixed
*/
public static function xmlDeserialize(Xml\Reader $reader)
public static function xmlDeserialize(Xml\Reader $reader): Uri
{
return new self(
\Sabre\Uri\resolve(
resolve(
(string) $reader->contextUri,
$reader->readText()
)

View file

@ -26,10 +26,8 @@ class XmlFragment implements Element
{
/**
* The inner XML value.
*
* @var string
*/
protected $xml;
protected string $xml;
/**
* Constructor.
@ -63,7 +61,7 @@ class XmlFragment implements Element
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Writer $writer)
public function xmlSerialize(Writer $writer): void
{
$reader = new Reader();
@ -135,10 +133,8 @@ XML;
*
* $reader->parseInnerTree() will parse the entire sub-tree, and advance to
* the next element.
*
* @return mixed
*/
public static function xmlDeserialize(Reader $reader)
public static function xmlDeserialize(Reader $reader): XmlFragment
{
$result = new self($reader->readInnerXml());
$reader->next();

View file

@ -23,7 +23,7 @@ class LibXMLException extends ParseException
*
* @var \LibXMLError[]
*/
protected $errors;
protected array $errors;
/**
* Creates the exception.
@ -31,7 +31,6 @@ class LibXMLException extends ParseException
* You should pass a list of LibXMLError objects in its constructor.
*
* @param LibXMLError[] $errors
* @param Throwable $previousException
*/
public function __construct(array $errors, int $code = 0, Throwable $previousException = null)
{
@ -41,6 +40,8 @@ class LibXMLException extends ParseException
/**
* Returns the LibXML errors.
*
* @return LibXMLError[]
*/
public function getErrors(): array
{

View file

@ -30,10 +30,8 @@ class Reader extends XMLReader
* Or if no namespace is defined: "{}feed".
*
* This method returns null if we're not currently on an element.
*
* @return string|null
*/
public function getClark()
public function getClark(): ?string
{
if (!$this->localName) {
return null;
@ -52,6 +50,8 @@ class Reader extends XMLReader
*
* This function will also disable the standard libxml error handler (which
* usually just results in PHP errors), and throw exceptions instead.
*
* @return array<string, mixed>
*/
public function parse(): array
{
@ -102,6 +102,10 @@ class Reader extends XMLReader
*
* If the $elementMap argument is specified, the existing elementMap will
* be overridden while parsing the tree, and restored after this process.
*
* @param array<string, mixed>|null $elementMap
*
* @return array<string, mixed>
*/
public function parseGetElements(array $elementMap = null): array
{
@ -124,7 +128,9 @@ class Reader extends XMLReader
* If the $elementMap argument is specified, the existing elementMap will
* be overridden while parsing the tree, and restored after this process.
*
* @return array|string|null
* @param array<string, mixed>|null $elementMap
*
* @return array<string, mixed>|string|null
*/
public function parseInnerTree(array $elementMap = null)
{
@ -193,7 +199,7 @@ class Reader extends XMLReader
}
}
return $elements ? $elements : $text;
return $elements ?: $text;
}
/**
@ -220,6 +226,8 @@ class Reader extends XMLReader
* * name - A clark-notation XML element name.
* * value - The parsed value.
* * attributes - A key-value list of attributes.
*
* @return array <string, mixed>
*/
public function parseCurrentElement(): array
{
@ -250,6 +258,8 @@ class Reader extends XMLReader
* If the attributes are part of the same namespace, they will simply be
* short keys. If they are defined on a different namespace, the attribute
* name will be returned in clark-notation.
*
* @return array<string, mixed>
*/
public function parseAttributes(): array
{
@ -297,9 +307,9 @@ class Reader extends XMLReader
}
$type = gettype($deserializer);
if ('string' === $type) {
if (is_string($deserializer)) {
$type .= ' ('.$deserializer.')';
} elseif ('object' === $type) {
} elseif (is_object($deserializer)) {
$type .= ' ('.get_class($deserializer).')';
}
throw new \LogicException('Could not use this type as a deserializer: '.$type.' for element: '.$name);

View file

@ -38,7 +38,7 @@ use Sabre\Xml\XmlSerializable;
*
* @param string[] $values
*/
function enum(Writer $writer, array $values)
function enum(Writer $writer, array $values): void
{
foreach ($values as $value) {
$writer->writeElement($value);
@ -53,10 +53,8 @@ function enum(Writer $writer, array $values)
*
* Values that are set to null or an empty array are not serialized. To
* serialize empty properties, you must specify them as an empty string.
*
* @param object $valueObject
*/
function valueObject(Writer $writer, $valueObject, string $namespace)
function valueObject(Writer $writer, object $valueObject, string $namespace): void
{
foreach (get_object_vars($valueObject) as $key => $val) {
if (is_array($val)) {
@ -85,8 +83,10 @@ function valueObject(Writer $writer, $valueObject, string $namespace)
* and this could be called like this:
*
* repeatingElements($writer, $items, '{}item');
*
* @param array<int,mixed> $items
*/
function repeatingElements(Writer $writer, array $items, string $childElementName)
function repeatingElements(Writer $writer, array $items, string $childElementName): void
{
foreach ($items as $item) {
$writer->writeElement($childElementName, $item);
@ -104,7 +104,7 @@ function repeatingElements(Writer $writer, array $items, string $childElementNam
* calls it's xmlSerialize() method.
* $value may be a PHP callback/function/closure, in case we call the callback
* and give it the Writer as an argument.
* $value may be a an object, and if it's in the classMap we automatically call
* $value may be an object, and if it's in the classMap we automatically call
* the correct serializer for it.
* $value may be null, in which case we do nothing.
*
@ -148,9 +148,9 @@ function repeatingElements(Writer $writer, array $items, string $childElementNam
*
* You can even mix the two array syntaxes.
*
* @param string|int|float|bool|array|object $value
* @param string|int|float|bool|array<int|string, mixed>|object $value
*/
function standardSerializer(Writer $writer, $value)
function standardSerializer(Writer $writer, $value): void
{
if (is_scalar($value)) {
// String, integer, float, boolean

View file

@ -26,9 +26,9 @@ class Service
* Values may also be a callable. In that case the function will be called
* directly.
*
* @var array
* @phpstan-var array<string, class-string|callable|object>
*/
public $elementMap = [];
public array $elementMap = [];
/**
* This is a list of namespaces that you want to give default prefixes.
@ -36,9 +36,9 @@ class Service
* You must make sure you create this entire list before starting to write.
* They should be registered on the root element.
*
* @var array
* @phpstan-var array<string, class-string|string|null>
*/
public $namespaceMap = [];
public array $namespaceMap = [];
/**
* This is a list of custom serializers for specific classes.
@ -56,16 +56,14 @@ class Service
*
* function (Writer $writer, object $value)
*
* @var array
* @phpstan-var array<class-string, callable(Writer, object):mixed>
*/
public $classMap = [];
public array $classMap = [];
/**
* A bitmask of the LIBXML_* constants.
*
* @var int
*/
public $options = 0;
public int $options = 0;
/**
* Returns a fresh XML Reader.
@ -107,7 +105,7 @@ class Service
*
* @throws ParseException
*
* @return array|object|string
* @return array<string, mixed>|object|string
*/
public function parse($input, string $contextUri = null, string &$rootElementName = null)
{
@ -151,7 +149,7 @@ class Service
*
* @throws ParseException
*
* @return array|object|string
* @return array<string, mixed>|object|string
*/
public function expect($rootElementName, $input, string $contextUri = null)
{
@ -200,11 +198,9 @@ class Service
* This allows an implementor to easily create URI's relative to the root
* of the domain.
*
* @param string|array|object|XmlSerializable $value
*
* @return string
* @param string|array<string, mixed>|object|XmlSerializable $value
*/
public function write(string $rootElementName, $value, string $contextUri = null)
public function write(string $rootElementName, $value, string $contextUri = null): string
{
$w = $this->getWriter();
$w->openMemory();
@ -239,8 +235,10 @@ class Service
* These can easily be mapped by calling:
*
* $service->mapValueObject('{http://example.org}author', 'Author');
*
* @param class-string $className
*/
public function mapValueObject(string $elementName, string $className)
public function mapValueObject(string $elementName, string $className): void
{
list($namespace) = self::parseClarkNotation($elementName);
@ -248,7 +246,7 @@ class Service
return \Sabre\Xml\Deserializer\valueObject($reader, $className, $namespace);
};
$this->classMap[$className] = function (Writer $writer, $valueObject) use ($namespace) {
return \Sabre\Xml\Serializer\valueObject($writer, $valueObject, $namespace);
\Sabre\Xml\Serializer\valueObject($writer, $valueObject, $namespace);
};
$this->valueObjectMap[$className] = $elementName;
}
@ -262,11 +260,9 @@ class Service
* The ValueObject must have been previously registered using
* mapValueObject().
*
* @param object $object
*
* @throws \InvalidArgumentException
*@throws \InvalidArgumentException
*/
public function writeValueObject($object, string $contextUri = null)
public function writeValueObject(object $object, string $contextUri = null): string
{
if (!isset($this->valueObjectMap[get_class($object)])) {
throw new \InvalidArgumentException('"'.get_class($object).'" is not a registered value object class. Register your class with mapValueObject.');
@ -286,6 +282,8 @@ class Service
* If the string was invalid, it will throw an InvalidArgumentException.
*
* @throws \InvalidArgumentException
*
* @return array{string|null, string}
*/
public static function parseClarkNotation(string $str): array
{
@ -307,6 +305,8 @@ class Service
/**
* A list of classes and which XML elements they map to.
*
* @var array<class-string, string>
*/
protected $valueObjectMap = [];
protected array $valueObjectMap = [];
}

View file

@ -16,5 +16,5 @@ class Version
/**
* Full version number.
*/
const VERSION = '2.2.5';
public const VERSION = '3.0.0';
}

View file

@ -41,19 +41,17 @@ class Writer extends XMLWriter
* time* they are used, but this array allows the writer to make sure that
* the prefixes are consistent anyway.
*
* @var array
* @var array<string, string>
*/
protected $adhocNamespaces = [];
protected array $adhocNamespaces = [];
/**
* When the first element is written, this flag is set to true.
*
* This ensures that the namespaces in the namespaces map are only written
* once.
*
* @var bool
*/
protected $namespacesWritten = false;
protected bool $namespacesWritten = false;
/**
* Writes a value to the output stream.
@ -96,16 +94,15 @@ class Writer extends XMLWriter
*
* @param mixed $value
*/
public function write($value)
public function write($value): void
{
require_once __DIR__ . '/Serializer/functions.php';
Serializer\standardSerializer($this, $value);
}
/**
* Opens a new element.
*
* You can either just use a local elementname, or you can use clark-
* You can either just use a local element name, or you can use clark-
* notation to start a new element.
*
* Example:
@ -118,6 +115,7 @@ class Writer extends XMLWriter
*
* Note: this function doesn't have the string typehint, because PHP's
* XMLWriter::startElement doesn't either.
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
*
* @param string $name
*/
@ -152,7 +150,7 @@ class Writer extends XMLWriter
if (!$this->namespacesWritten) {
foreach ($this->namespaceMap as $namespace => $prefix) {
$this->writeAttribute(($prefix ? 'xmlns:'.$prefix : 'xmlns'), $namespace);
$this->writeAttribute($prefix ? 'xmlns:'.$prefix : 'xmlns', $namespace);
}
$this->namespacesWritten = true;
}
@ -181,8 +179,10 @@ class Writer extends XMLWriter
*
* Note: this function doesn't have the string typehint, because PHP's
* XMLWriter::startElement doesn't either.
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
*
* @param array|string|object|null $content
* @param string $name
* @param array<int|string, mixed>|string|object|null $content
*/
public function writeElement($name, $content = null): bool
{
@ -203,8 +203,10 @@ class Writer extends XMLWriter
* The key is an attribute name. If the key is a 'localName', the current
* xml namespace is assumed. If it's a 'clark notation key', this namespace
* will be used instead.
*
* @param array<string, string> $attributes
*/
public function writeAttributes(array $attributes)
public function writeAttributes(array $attributes): void
{
foreach ($attributes as $name => $value) {
$this->writeAttribute($name, $value);
@ -220,6 +222,7 @@ class Writer extends XMLWriter
*
* Note: this function doesn't have typehints, because for some reason
* PHP's XMLWriter::writeAttribute doesn't either.
* From PHP 8.0 the typehint exists, so it can be added here after PHP 7.4 is dropped.
*
* @param string $name
* @param string $value

View file

@ -30,5 +30,5 @@ interface XmlSerializable
*
* If you are opening new elements, you must also close them again.
*/
public function xmlSerialize(Writer $writer);
public function xmlSerialize(Writer $writer): void;
}