diff --git a/.github/workflows/test-lang-php.yml b/.github/workflows/test-lang-php.yml
index 883ef5ce115..6bb145f6100 100644
--- a/.github/workflows/test-lang-php.yml
+++ b/.github/workflows/test-lang-php.yml
@@ -42,9 +42,6 @@ jobs:
- ubuntu-latest
- ubuntu-24.04-arm
php:
- - '7.3'
- - '7.4'
- - '8.0'
- '8.1'
- '8.2'
- '8.3'
@@ -71,8 +68,12 @@ jobs:
${{ runner.os }}-composer-
- name: Lint
+ if: matrix.php.version == '8.1'
run: ./build.sh lint
+ - name: Static analysis
+ run: ./build.sh phpstan
+
- name: Test
run: ./build.sh test
@@ -84,9 +85,6 @@ jobs:
- ubuntu-latest
- ubuntu-24.04-arm
php:
- - '7.3'
- - '7.4'
- - '8.0'
- '8.1'
- '8.2'
- '8.3'
diff --git a/composer.json b/composer.json
index 3b5e06ef219..ec5d2a3f37b 100644
--- a/composer.json
+++ b/composer.json
@@ -23,20 +23,21 @@
"issues": "https://issues.apache.org/jira/browse/AVRO"
},
"require": {
- "php": "^7.3 || ^8.0"
+ "php": "^8.1"
},
"deps": [
- "vendor/phpunit/phpunit",
- "vendor/squizlabs/php_codesniffer"
+ "vendor/phpunit/phpunit"
],
"require-dev": {
- "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
- "squizlabs/php_codesniffer": "3.*",
+ "phpunit/phpunit": "^10.5",
"php-mock/php-mock-phpunit": "^2.10",
"ext-json": "*",
"ext-xml": "*",
"ext-curl": "*",
- "ext-pcntl": "*"
+ "ext-pcntl": "*",
+ "rector/rector": "^2.2",
+ "friendsofphp/php-cs-fixer": "^3.89",
+ "phpstan/phpstan": "^2.1"
},
"autoload": {
"psr-4": {
diff --git a/lang/php/.gitignore b/lang/php/.gitignore
index d2429e1abce..e691e824604 100644
--- a/lang/php/.gitignore
+++ b/lang/php/.gitignore
@@ -1,3 +1,5 @@
pkg
vendor
.phpunit.result.cache
+.phpunit.cache
+.php-cs-fixer.cache
diff --git a/lang/php/.php-cs-fixer.dist.php b/lang/php/.php-cs-fixer.dist.php
new file mode 100644
index 00000000000..84f9fcd711a
--- /dev/null
+++ b/lang/php/.php-cs-fixer.dist.php
@@ -0,0 +1,102 @@
+ php-cs-fixer describe blank_line_before_statement
+ * ```
+ */
+$finder = PhpCsFixer\Finder::create()
+ ->in(['test'])
+ ->append(['.php-cs-fixer.dist.php']);
+
+return (new PhpCsFixer\Config())
+ ->setRiskyAllowed(true)
+ ->setParallelConfig(ParallelConfigFactory::detect())
+ ->setRules([
+ // —— CS Rule Sets —————————————————————————————————————————————————————
+ '@Symfony' => true,
+ '@PHP8x0Migration' => true,
+
+ // —— Overriden rules ——————————————————————————————————————————————————
+
+ // @Symfony: `['statements' => ['return']]`
+ // Here using: default, `['statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try']]`
+ 'blank_line_before_statement' => true,
+
+ // @Symfony: `['tokens' => [['attribute', 'case', 'continue', 'curly_brace_block', 'default', 'extra', 'parenthesis_brace_block', 'square_brace_block', 'switch', 'throw', 'use']]]`
+ // Here using: default, `['tokens' => ['extra']]`
+ 'no_extra_blank_lines' => true,
+
+ // @Symfony: `['allow_hidden_params' => true, 'remove_inheritdoc' => true]`
+ 'no_superfluous_phpdoc_tags' => ['allow_mixed' => true, 'allow_unused_params' => true, 'remove_inheritdoc' => false],
+
+ // @Symfony: `['after_heredoc' => true]`
+ // Here using: default, `['after_heredoc' => false]`
+ 'no_whitespace_before_comma_in_array' => true,
+
+ // @Symfony: `['order' => ['use_trait']]`
+ // Here using: default, `['order' => ['use_trait', 'case', 'constant_public', 'constant_protected', 'constant_private', 'property_public', 'property_protected', 'property_private', 'construct', 'destruct', 'magic', 'phpunit', 'method_public', 'method_protected', 'method_private']]`)
+ 'ordered_class_elements' => true,
+
+ // @Symfony: `['imports_order' => ['class', 'function', 'const'], 'sort_algorithm' => 'alpha']`
+ // Here using: default, all import types (classes, functions, and constants) are sorted together alphabetically without grouping them by type
+ 'ordered_imports' => true,
+
+ // @Symfony: `['order' => ['param', 'return', 'throws']]`
+ // Here using: default, `['param', 'throws', 'return']`
+ 'phpdoc_order' => true,
+
+ // @Symfony: `['null_adjustment' => 'always_last', 'sort_algorithm' => 'none']`
+ 'phpdoc_types_order' => ['null_adjustment' => 'always_first'],
+
+ // @Symfony: `['case' => 'camel_case']`
+ 'php_unit_method_casing' => ['case' => 'snake_case'],
+
+ // —— Overriden rules (disabled) ————————————————————————————————————————
+ // @Symfony
+ 'increment_style' => false,
+ 'phpdoc_align' => false,
+ 'phpdoc_separation' => false,
+ 'phpdoc_summary' => false,
+ 'phpdoc_to_comment' => false,
+ 'single_line_comment_style' => false,
+ 'single_line_throw' => false,
+ 'single_quote' => false,
+
+ // —— Additional rules ——————————————————————————————————————————————————
+ 'no_useless_else' => true,
+ 'phpdoc_add_missing_param_annotation' => true,
+ 'protected_to_private' => true,
+ 'psr_autoloading' => true,
+ ])
+ ->setFinder($finder)
+;
diff --git a/lang/php/README.md b/lang/php/README.md
index 9aa12d943be..991cfc457a2 100644
--- a/lang/php/README.md
+++ b/lang/php/README.md
@@ -8,14 +8,14 @@ A library for using [Avro](https://avro.apache.org/) with PHP.
Requirements
============
- * PHP 7.3+
+ * PHP 8.1+
* On 32-bit platforms, the [GMP PHP extension](https://php.net/gmp)
* For Zstandard compression, [ext-zstd](https://github.com/kjdev/php-ext-zstd)
* For Snappy compression, [ext-snappy](https://github.com/kjdev/php-ext-snappy)
* For testing, [PHPUnit](https://www.phpunit.de/)
Both GMP and PHPUnit are often available via package management
-systems as `php7-gmp` and `phpunit`, respectively.
+systems as `php8.1-gmp` and `phpunit`, respectively.
Getting started
diff --git a/lang/php/build.sh b/lang/php/build.sh
index 8b5497001cb..bb4595f8bb0 100755
--- a/lang/php/build.sh
+++ b/lang/php/build.sh
@@ -59,13 +59,22 @@ do
lint)
composer install -d "../.."
- find . -name "*.php" -print0 | xargs -0 -n1 -P8 php -l
- ../../vendor/bin/phpcs --standard=PSR12 lib
+ ../../vendor/bin/php-cs-fixer fix --dry-run --show-progress=dots --verbose --diff --no-interaction
+ ;;
+
+ lint-fix)
+ composer install -d "../.."
+ ../../vendor/bin/php-cs-fixer fix --show-progress=dots --verbose --diff
+ ;;
+
+ phpstan)
+ composer install -d "../.."
+ ../../vendor/bin/phpstan
;;
test)
composer install -d "../.."
- ../../vendor/bin/phpunit -v
+ ../../vendor/bin/phpunit
;;
dist)
@@ -77,7 +86,7 @@ do
;;
*)
- echo "Usage: $0 {interop-data-generate|test-interop|lint|test|dist|clean}"
+ echo "Usage: $0 {interop-data-generate|test-interop|lint|lint-fix|test|dist|clean}"
esac
done
diff --git a/lang/php/examples/write_read.php b/lang/php/examples/write_read.php
index b5c1a69b9f3..2c4e8b0e378 100644
--- a/lang/php/examples/write_read.php
+++ b/lang/php/examples/write_read.php
@@ -37,9 +37,9 @@
{"name":"member_name", "type":"string"}]}
_JSON;
-$jose = array('member_id' => 1392, 'member_name' => 'Jose');
-$maria = array('member_id' => 1642, 'member_name' => 'Maria');
-$data = array($jose, $maria);
+$jose = ['member_id' => 1392, 'member_name' => 'Jose'];
+$maria = ['member_id' => 1642, 'member_name' => 'Maria'];
+$data = [$jose, $maria];
$file_name = 'data.avr';
// Open $file_name for writing, using the given writer's schema
diff --git a/lang/php/lib/Avro.php b/lang/php/lib/Avro.php
index 8e032bc52a2..7c537ca8c2d 100644
--- a/lang/php/lib/Avro.php
+++ b/lang/php/lib/Avro.php
@@ -46,13 +46,12 @@ class Avro
private const GMP_BIGINTEGER_MODE = 0x01;
/**#@-*/
/**
- * @var int
* Mode used to handle bigintegers. After Avro::check64Bit() has been called,
* (usually via a call to Avro::checkPlatform(), set to
* self::GMP_BIGINTEGER_MODE on 32-bit platforms that have GMP available,
* and to self::PHP_BIGINTEGER_MODE otherwise.
*/
- private static $biginteger_mode;
+ private static int $biginteger_mode;
/**
* Wrapper method to call each required check.
@@ -70,7 +69,7 @@ public static function checkPlatform()
*/
private static function check64Bit()
{
- if (8 != PHP_INT_SIZE) {
+ if (8 !== PHP_INT_SIZE) {
if (extension_loaded('gmp')) {
self::$biginteger_mode = self::GMP_BIGINTEGER_MODE;
} else {
@@ -83,11 +82,11 @@ private static function check64Bit()
}
/**
- * @returns boolean true if the PHP GMP extension is used and false otherwise.
+ * @returns bool true if the PHP GMP extension is used and false otherwise.
* @internal Requires Avro::check64Bit() (exposed via Avro::checkPlatform())
* to have been called to set Avro::$biginteger_mode.
*/
- public static function usesGmp()
+ public static function usesGmp(): bool
{
return self::GMP_BIGINTEGER_MODE === self::$biginteger_mode;
}
diff --git a/lang/php/lib/AvroDebug.php b/lang/php/lib/AvroDebug.php
index 777dcd9b24a..d3beb106201 100644
--- a/lang/php/lib/AvroDebug.php
+++ b/lang/php/lib/AvroDebug.php
@@ -55,12 +55,11 @@ public static function debug($format, $args, $debug_level = self::DEBUG1)
}
/**
- * @var int $debug_level
- * @returns boolean true if the given $debug_level is equivalent
+ * @return boolean true if the given $debug_level is equivalent
* or more verbose than than the current debug level
* and false otherwise.
*/
- public static function isDebug($debug_level = self::DEBUG1)
+ public static function isDebug(int $debug_level = self::DEBUG1): bool
{
return (self::DEBUG_LEVEL >= $debug_level);
}
@@ -92,7 +91,7 @@ public static function hexArray($str)
*/
public static function bytesArray($str, $format = 'x%02x')
{
- $x = array();
+ $x = [];
foreach (str_split($str) as $b) {
$x[] = sprintf($format, ord($b));
}
@@ -151,7 +150,7 @@ public static function asciiArray($str, $format = 'ctrl')
throw new AvroException('Unrecognized format specifier');
}
- $ctrl_chars = array(
+ $ctrl_chars = [
'NUL',
'SOH',
'STX',
@@ -184,8 +183,8 @@ public static function asciiArray($str, $format = 'ctrl')
'GS',
'RS',
'US'
- );
- $x = array();
+ ];
+ $x = [];
foreach (str_split($str) as $b) {
$db = ord($b);
if ($db < 32) {
diff --git a/lang/php/lib/AvroGMP.php b/lang/php/lib/AvroGMP.php
index c868cf17a66..e4309668e4f 100644
--- a/lang/php/lib/AvroGMP.php
+++ b/lang/php/lib/AvroGMP.php
@@ -32,32 +32,32 @@
class AvroGMP
{
/**
- * @var resource memoized GMP resource for zero
+ * @var \GMP memoized GMP resource for zero
*/
private static $gmp_0;
/**
- * @var resource memoized GMP resource for one (1)
+ * @var \GMP memoized GMP resource for one (1)
*/
private static $gmp_1;
/**
- * @var resource memoized GMP resource for two (2)
+ * @var \GMP memoized GMP resource for two (2)
*/
private static $gmp_2;
/**
- * @var resource memoized GMP resource for 0x7f
+ * @var \GMP memoized GMP resource for 0x7f
*/
private static $gmp_0x7f;
/**
- * @var resource memoized GMP resource for 64-bit ~0x7f
+ * @var \GMP memoized GMP resource for 64-bit ~0x7f
*/
private static $gmp_n0x7f;
/**
- * @var resource memoized GMP resource for 64-bits of 1
+ * @var \GMP memoized GMP resource for 64-bits of 1
*/
private static $gmp_0xfs;
/**
- * @param int|str $n integer (or string representation of integer) to encode
+ * @param int|string $n integer (or string representation of integer) to encode
* @return string $bytes of the long $n encoded per the Avro spec
*/
public static function encodeLong($n)
@@ -104,8 +104,8 @@ public static function shiftLeft($g, $shift)
}
/**
- * @param GMP resource
- * @returns GMP resource 64-bit two's complement of input.
+ * @param \GMP $g resource
+ * @return \GMP resource 64-bit two's complement of input.
*/
public static function gmpTwosComplement($g)
{
@@ -147,7 +147,7 @@ public static function shiftRight($g, $shift)
// phpcs:disable PSR1.Methods.CamelCapsMethodName
/**
- * @returns resource GMP resource for two (2)
+ * @returns \GMP GMP resource for two (2)
*/
private static function gmp_2()
{
diff --git a/lang/php/lib/AvroIO.php b/lang/php/lib/AvroIO.php
index 30cd94e8066..9a6f5825233 100644
--- a/lang/php/lib/AvroIO.php
+++ b/lang/php/lib/AvroIO.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro;
/**
@@ -26,7 +28,7 @@
*
* @package Avro
*/
-class AvroIO
+interface AvroIO
{
/**
* @var string general read mode
@@ -52,33 +54,21 @@ class AvroIO
/**
* Read $len bytes from AvroIO instance
- * @return string bytes read
- * @var int $len
*/
- public function read($len)
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function read(int $len): string;
/**
* Append bytes to this buffer. (Nothing more is needed to support Avro.)
- * @param string $arg bytes to write
+ * @param string $bytes bytes to write
* @returns int count of bytes written.
* @throws IO\AvroIOException if $args is not a string value.
*/
- public function write($arg)
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function write(string $bytes): int;
/**
* Return byte offset within AvroIO instance
- * @return int
*/
- public function tell()
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function tell(): int;
/**
* Set the position indicator. The new position, measured in bytes
@@ -92,19 +82,13 @@ public function tell()
*
* @throws IO\AvroIOException
*/
- public function seek($offset, $whence = self::SEEK_SET): bool
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function seek(int $offset, int $whence = self::SEEK_SET): bool;
/**
* Flushes any buffered data to the AvroIO object.
- * @returns boolean true upon success.
+ * @returns bool true upon success.
*/
- public function flush()
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function flush(): bool;
/**
* Returns whether or not the current position at the end of this AvroIO
@@ -113,18 +97,12 @@ public function flush()
* Note isEof() is not like eof in C or feof in PHP:
* it returns TRUE if the *next* read would be end of file,
* rather than if the *most recent* read read end of file.
- * @returns boolean true if at the end of file, and false otherwise
+ * @returns bool true if at the end of file, and false otherwise
*/
- public function isEof()
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function isEof(): bool;
/**
* Closes this AvroIO instance.
*/
- public function close()
- {
- throw new AvroNotImplementedException('Not implemented');
- }
+ public function close(): bool;
}
diff --git a/lang/php/lib/DataFile/AvroDataIO.php b/lang/php/lib/DataFile/AvroDataIO.php
index aaea5bdb140..7fe75854946 100644
--- a/lang/php/lib/DataFile/AvroDataIO.php
+++ b/lang/php/lib/DataFile/AvroDataIO.php
@@ -99,7 +99,7 @@ class AvroDataIO
*/
public static function magicSize()
{
- return strlen(self::magic());
+ return strlen((string) self::magic());
}
/**
diff --git a/lang/php/lib/DataFile/AvroDataIOReader.php b/lang/php/lib/DataFile/AvroDataIOReader.php
index 0dc4dd0ee45..3dd85ff06eb 100644
--- a/lang/php/lib/DataFile/AvroDataIOReader.php
+++ b/lang/php/lib/DataFile/AvroDataIOReader.php
@@ -25,6 +25,7 @@
use Apache\Avro\AvroUtil;
use Apache\Avro\Datum\AvroIOBinaryDecoder;
use Apache\Avro\Datum\AvroIODatumReader;
+use Apache\Avro\IO\AvroIOException;
use Apache\Avro\IO\AvroStringIO;
use Apache\Avro\Schema\AvroSchema;
@@ -35,35 +36,24 @@
*/
class AvroDataIOReader
{
- /**
- * @var string
- */
- public $sync_marker;
+ public string $sync_marker;
/**
* @var array object container metadata
*/
- public $metadata;
- /**
- * @var AvroIO
- */
- private $io;
- /**
- * @var AvroIOBinaryDecoder
- */
- private $decoder;
- /**
- * @var AvroIODatumReader
- */
- private $datum_reader;
+ public array $metadata;
+
+ private AvroIO $io;
+
+ private AvroIOBinaryDecoder $decoder;
/**
* @var int count of items in block
*/
- private $block_count;
+ private int $block_count;
/**
- * @var compression codec
+ * @var string compression codec
*/
- private $codec;
+ private string $codec;
/**
* @param AvroIO $io source from which to read
@@ -74,16 +64,12 @@ class AvroDataIOReader
* is not supported
* @uses readHeader()
*/
- public function __construct($io, $datum_reader)
- {
-
- if (!($io instanceof AvroIO)) {
- throw new AvroDataIOException('io must be instance of AvroIO');
- }
-
+ public function __construct(
+ AvroIO $io,
+ private AvroIODatumReader $datum_reader
+ ) {
$this->io = $io;
$this->decoder = new AvroIOBinaryDecoder($this->io);
- $this->datum_reader = $datum_reader;
$this->readHeader();
$codec = $this->metadata[AvroDataIO::METADATA_CODEC_ATTR] ?? null;
@@ -104,13 +90,13 @@ public function __construct($io, $datum_reader)
* Reads header of object container
* @throws AvroDataIOException if the file is not an Avro data file.
*/
- private function readHeader()
+ private function readHeader(): void
{
$this->seek(0, AvroIO::SEEK_SET);
$magic = $this->read(AvroDataIO::magicSize());
- if (strlen($magic) < AvroDataIO::magicSize()) {
+ if (strlen((string) $magic) < AvroDataIO::magicSize()) {
throw new AvroDataIOException(
'Not an Avro data file: shorter than the Avro magic block'
);
@@ -137,7 +123,7 @@ private function readHeader()
/**
* @uses AvroIO::seek()
*/
- private function seek($offset, $whence)
+ private function seek($offset, $whence): bool
{
return $this->io->seek($offset, $whence);
}
@@ -145,16 +131,18 @@ private function seek($offset, $whence)
/**
* @uses AvroIO::read()
*/
- private function read($len)
+ private function read($len): string
{
return $this->io->read($len);
}
/**
+ * @return array of data from object container.
+ * @throws AvroException
+ * @throws AvroIOException
* @internal Would be nice to implement data() as an iterator, I think
- * @returns array of data from object container.
*/
- public function data()
+ public function data(): array
{
$data = [];
$decoder = $this->decoder;
@@ -187,8 +175,8 @@ public function data()
throw new AvroException('Please install ext-snappy to use snappy compression.');
}
$compressed = $decoder->read($length);
- $crc32 = unpack('N', substr($compressed, -4))[1];
- $datum = snappy_uncompress(substr($compressed, 0, -4));
+ $crc32 = unpack('N', substr((string) $compressed, -4))[1];
+ $datum = snappy_uncompress(substr((string) $compressed, 0, -4));
if ($crc32 === crc32($datum)) {
$decoder = new AvroIOBinaryDecoder(new AvroStringIO($datum));
} else {
@@ -212,12 +200,12 @@ public function data()
/**
* @uses AvroIO::isEof()
*/
- private function isEof()
+ private function isEof(): bool
{
return $this->io->isEof();
}
- private function skipSync()
+ private function skipSync(): bool
{
$proposed_sync_marker = $this->read(AvroDataIO::SYNC_SIZE);
if ($proposed_sync_marker != $this->sync_marker) {
@@ -232,7 +220,7 @@ private function skipSync()
* and the length in bytes of the block)
* @returns int length in bytes of the block.
*/
- private function readBlockHeader()
+ private function readBlockHeader(): string|int
{
$this->block_count = $this->decoder->readLong();
return $this->decoder->readLong();
@@ -242,7 +230,7 @@ private function readBlockHeader()
* Closes this writer (and its AvroIO object.)
* @uses AvroIO::close()
*/
- public function close()
+ public function close(): bool
{
return $this->io->close();
}
diff --git a/lang/php/lib/DataFile/AvroDataIOWriter.php b/lang/php/lib/DataFile/AvroDataIOWriter.php
index b28143723d7..edfdee91be5 100644
--- a/lang/php/lib/DataFile/AvroDataIOWriter.php
+++ b/lang/php/lib/DataFile/AvroDataIOWriter.php
@@ -37,59 +37,52 @@ class AvroDataIOWriter
/**
* @var AvroIO object container where data is written
*/
- private $io;
+ private AvroIO $io;
/**
* @var AvroIOBinaryEncoder encoder for object container
*/
- private $encoder;
- /**
- * @var AvroIODatumWriter
- */
- private $datum_writer;
+ private AvroIOBinaryEncoder $encoder;
/**
* @var AvroStringIO buffer for writing
*/
- private $buffer;
+ private AvroStringIO $buffer;
+
+ private AvroIODatumWriter $datum_writer;
+
/**
* @var AvroIOBinaryEncoder encoder for buffer
*/
- private $buffer_encoder;
+ private AvroIOBinaryEncoder $buffer_encoder;
/**
* @var int count of items written to block
*/
- private $block_count; // AvroIOBinaryEncoder
+ private int $block_count;
/**
* @var array map of object container metadata
*/
- private $metadata;
+ private array $metadata;
/**
* @var string compression codec
*/
- private $codec;
+ private string $codec;
/**
* @var string sync marker
*/
- private $sync_marker;
-
- /**
- * @param AvroIO $io
- * @param AvroIODatumWriter $datum_writer
- * @param AvroSchema $writers_schema
- * @param string $codec
- */
- public function __construct($io, $datum_writer, $writers_schema = null, $codec = AvroDataIO::NULL_CODEC)
- {
- if (!($io instanceof AvroIO)) {
- throw new AvroDataIOException('io must be instance of AvroIO');
- }
+ private string $sync_marker;
+ public function __construct(
+ AvroIO $io,
+ AvroIODatumWriter $datum_writer,
+ null|string|AvroSchema $writers_schema = null,
+ string $codec = AvroDataIO::NULL_CODEC
+ ) {
$this->io = $io;
- $this->encoder = new AvroIOBinaryEncoder($this->io);
$this->datum_writer = $datum_writer;
+ $this->encoder = new AvroIOBinaryEncoder($this->io);
$this->buffer = new AvroStringIO();
$this->buffer_encoder = new AvroIOBinaryEncoder($this->buffer);
$this->block_count = 0;
- $this->metadata = array();
+ $this->metadata = [];
if ($writers_schema) {
if (!AvroDataIO::isValidCodec($codec)) {
diff --git a/lang/php/lib/Datum/AvroIOBinaryDecoder.php b/lang/php/lib/Datum/AvroIOBinaryDecoder.php
index 31a007f0ac9..98d3111ec37 100644
--- a/lang/php/lib/Datum/AvroIOBinaryDecoder.php
+++ b/lang/php/lib/Datum/AvroIOBinaryDecoder.php
@@ -25,6 +25,12 @@
use Apache\Avro\AvroException;
use Apache\Avro\AvroGMP;
use Apache\Avro\AvroIO;
+use Apache\Avro\Schema\AvroArraySchema;
+use Apache\Avro\Schema\AvroFixedSchema;
+use Apache\Avro\Schema\AvroMapSchema;
+use Apache\Avro\Schema\AvroRecordSchema;
+use Apache\Avro\Schema\AvroSchema;
+use Apache\Avro\Schema\AvroUnionSchema;
/**
* Decodes and reads Avro data from an AvroIO object encoded using
@@ -34,18 +40,13 @@
*/
class AvroIOBinaryDecoder
{
- /**
- * @var AvroIO
- */
- private $io;
-
/**
* @param AvroIO $io object from which to read.
*/
- public function __construct($io)
- {
+ public function __construct(
+ private AvroIO $io
+ ) {
Avro::checkPlatform();
- $this->io = $io;
}
/**
@@ -59,16 +60,16 @@ public function readNull()
/**
* @returns boolean
*/
- public function readBoolean()
+ public function readBoolean(): bool
{
- return (bool) (1 == ord($this->nextByte()));
+ return 1 === ord($this->nextByte());
}
/**
* @returns string the next byte from $this->io.
* @throws AvroException if the next byte cannot be read.
*/
- private function nextByte()
+ private function nextByte(): string
{
return $this->read(1);
}
@@ -77,15 +78,12 @@ private function nextByte()
* @param int $len count of bytes to read
* @returns string
*/
- public function read($len)
+ public function read(int $len): string
{
return $this->io->read($len);
}
- /**
- * @returns int
- */
- public function readInt()
+ public function readInt(): int
{
return (int) $this->readLong();
}
@@ -93,10 +91,10 @@ public function readInt()
/**
* @returns string|int
*/
- public function readLong()
+ public function readLong(): string|int
{
$byte = ord($this->nextByte());
- $bytes = array($byte);
+ $bytes = [$byte];
while (0 != ($byte & 0x80)) {
$byte = ord($this->nextByte());
$bytes [] = $byte;
@@ -110,11 +108,11 @@ public function readLong()
}
/**
- * @param int[] array of byte ascii values
- * @returns long decoded value
+ * @param int[] $bytes array of byte ascii values
+ * @return int decoded value
* @internal Requires 64-bit platform
*/
- public static function decodeLongFromArray($bytes)
+ public static function decodeLongFromArray(array $bytes): int
{
$b = array_shift($bytes);
$n = $b & 0x7f;
@@ -127,10 +125,7 @@ public static function decodeLongFromArray($bytes)
return ($n >> 1) ^ (($n >> 63) << 63) ^ -($n & 1);
}
- /**
- * @returns float
- */
- public function readFloat()
+ public function readFloat(): float
{
return self::intBitsToFloat($this->read(4));
}
@@ -140,11 +135,8 @@ public function readFloat()
*
* XXX: This is not endian-aware! See comments in
* {@link AvroIOBinaryEncoder::floatToIntBits()} for details.
- *
- * @param string $bits
- * @returns float
*/
- public static function intBitsToFloat($bits)
+ public static function intBitsToFloat(string $bits): float
{
$float = unpack('g', $bits);
return (float) $float[1];
@@ -153,7 +145,7 @@ public static function intBitsToFloat($bits)
/**
* @returns double
*/
- public function readDouble()
+ public function readDouble(): float
{
return self::longBitsToDouble($this->read(8));
}
@@ -164,13 +156,11 @@ public function readDouble()
* XXX: This is not endian-aware! See comments in
* {@link AvroIOBinaryEncoder::floatToIntBits()} for details.
*
- * @param string $bits
- * @returns float
*/
- public static function longBitsToDouble($bits)
+ public static function longBitsToDouble(string $bits)
{
$double = unpack('e', $bits);
- return (double) $double[1];
+ return (float) $double[1];
}
/**
@@ -178,7 +168,7 @@ public static function longBitsToDouble($bits)
* of UTF-8 encoded character data.
* @returns string
*/
- public function readString()
+ public function readString(): string
{
return $this->readBytes();
}
@@ -186,47 +176,44 @@ public function readString()
/**
* @returns string
*/
- public function readBytes()
+ public function readBytes(): string
{
return $this->read($this->readLong());
}
- public function skipNull()
+ public function skipNull(): void
{
- return null;
+ return;
}
- public function skipBoolean()
+ public function skipBoolean(): void
{
- return $this->skip(1);
+ $this->skip(1);
}
/**
* @param int $len count of bytes to skip
* @uses AvroIO::seek()
*/
- public function skip($len)
+ public function skip(int $len): void
{
$this->seek($len, AvroIO::SEEK_CUR);
}
/**
- * @param int $offset
- * @param int $whence
- * @returns boolean true upon success
* @uses AvroIO::seek()
*/
- private function seek($offset, $whence)
+ private function seek(int $offset, int $whence): bool
{
return $this->io->seek($offset, $whence);
}
- public function skipInt()
+ public function skipInt(): void
{
- return $this->skipLong();
+ $this->skipLong();
}
- public function skipLong()
+ public function skipLong(): void
{
$b = ord($this->nextByte());
while (0 != ($b & 0x80)) {
@@ -234,50 +221,50 @@ public function skipLong()
}
}
- public function skipFloat()
+ public function skipFloat(): void
{
- return $this->skip(4);
+ $this->skip(4);
}
- public function skipDouble()
+ public function skipDouble(): void
{
- return $this->skip(8);
+ $this->skip(8);
}
- public function skipString()
+ public function skipString(): void
{
- return $this->skipBytes();
+ $this->skipBytes();
}
- public function skipBytes()
+ public function skipBytes(): void
{
- return $this->skip($this->readLong());
+ $this->skip($this->readLong());
}
- public function skipFixed($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipFixed(AvroFixedSchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
$decoder->skip($writers_schema->size());
}
- public function skipEnum($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipEnum(AvroSchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
$decoder->skipInt();
}
- public function skipUnion($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipUnion(AvroUnionSchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
$index = $decoder->readLong();
AvroIODatumReader::skipData($writers_schema->schemaByIndex($index), $decoder);
}
- public function skipRecord($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipRecord(AvroRecordSchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
foreach ($writers_schema->fields() as $f) {
AvroIODatumReader::skipData($f->type(), $decoder);
}
}
- public function skipArray($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipArray(AvroArraySchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
$block_count = $decoder->readLong();
while (0 !== $block_count) {
@@ -291,7 +278,7 @@ public function skipArray($writers_schema, AvroIOBinaryDecoder $decoder)
}
}
- public function skipMap($writers_schema, AvroIOBinaryDecoder $decoder)
+ public function skipMap(AvroMapSchema $writers_schema, AvroIOBinaryDecoder $decoder): void
{
$block_count = $decoder->readLong();
while (0 !== $block_count) {
@@ -307,10 +294,10 @@ public function skipMap($writers_schema, AvroIOBinaryDecoder $decoder)
}
/**
- * @returns int position of pointer in AvroIO instance
+ * @return int position of pointer in AvroIO instance
* @uses AvroIO::tell()
*/
- private function tell()
+ private function tell(): int
{
return $this->io->tell();
}
diff --git a/lang/php/lib/Datum/AvroIOBinaryEncoder.php b/lang/php/lib/Datum/AvroIOBinaryEncoder.php
index 5f289aafa92..aa14cdc595a 100644
--- a/lang/php/lib/Datum/AvroIOBinaryEncoder.php
+++ b/lang/php/lib/Datum/AvroIOBinaryEncoder.php
@@ -33,19 +33,14 @@
*/
class AvroIOBinaryEncoder
{
- /**
- * @var AvroIO
- */
- private $io;
-
/**
* @param AvroIO $io object to which data is to be written.
*
*/
- public function __construct(AvroIO $io)
- {
+ public function __construct(
+ private readonly AvroIO $io
+ ) {
Avro::checkPlatform();
- $this->io = $io;
}
/**
@@ -56,35 +51,23 @@ public function writeNull($datum): void
return;
}
- /**
- * @param boolean $datum
- */
- public function writeBoolean($datum)
+ public function writeBoolean(bool $datum): void
{
$byte = $datum ? chr(1) : chr(0);
$this->write($byte);
}
- /**
- * @param string $datum
- */
- public function write($datum): void
+ public function write(string $datum): void
{
$this->io->write($datum);
}
- /**
- * @param int $datum
- */
- public function writeInt($datum): void
+ public function writeInt(int|string $datum): void
{
$this->writeLong($datum);
}
- /**
- * @param int $n
- */
- public function writeLong($n): void
+ public function writeLong(int|string $n): void
{
if (Avro::usesGmp()) {
$this->write(AvroGMP::encodeLong($n));
@@ -152,7 +135,7 @@ public static function floatToIntBits($float): string
* @param float $datum
* @uses self::doubleToLongBits()
*/
- public function writeDouble($datum): void
+ public function writeDouble(float $datum): void
{
$this->write(self::doubleToLongBits($datum));
}
@@ -172,30 +155,26 @@ public static function doubleToLongBits($double): string
}
/**
- * @param string $str
* @uses self::writeBytes()
*/
- public function writeString($str): void
+ public function writeString(string $str): void
{
$this->writeBytes($str);
}
- /**
- * @param string $bytes
- */
- public function writeBytes($bytes): void
+ public function writeBytes(string $bytes): void
{
$this->writeLong(strlen($bytes));
$this->write($bytes);
}
- public function writeDecimal($decimal, int $scale, int $precision): void
+ public function writeDecimal(string $decimal, int $scale, int $precision): void
{
if (!is_numeric($decimal)) {
throw new AvroException("Decimal value '{$decimal}' must be numeric");
}
- $value = $decimal * (10 ** $scale);
+ $value = ((float) $decimal) * (10 ** $scale);
if (!is_int($value)) {
$value = (int) round($value);
}
diff --git a/lang/php/lib/Datum/AvroIODatumReader.php b/lang/php/lib/Datum/AvroIODatumReader.php
index 24278a3dfb2..428886f4818 100644
--- a/lang/php/lib/Datum/AvroIODatumReader.php
+++ b/lang/php/lib/Datum/AvroIODatumReader.php
@@ -22,9 +22,17 @@
use Apache\Avro\AvroException;
use Apache\Avro\Datum\Type\AvroDuration;
+use Apache\Avro\Schema\AvroAliasedSchema;
+use Apache\Avro\Schema\AvroArraySchema;
+use Apache\Avro\Schema\AvroEnumSchema;
+use Apache\Avro\Schema\AvroFixedSchema;
use Apache\Avro\Schema\AvroLogicalType;
+use Apache\Avro\Schema\AvroMapSchema;
use Apache\Avro\Schema\AvroName;
+use Apache\Avro\Schema\AvroRecordSchema;
use Apache\Avro\Schema\AvroSchema;
+use Apache\Avro\Schema\AvroSchemaParseException;
+use Apache\Avro\Schema\AvroUnionSchema;
/**
* Handles schema-specifc reading of data from the decoder.
@@ -36,19 +44,10 @@
*/
class AvroIODatumReader
{
- /**
- * @var AvroSchema
- */
- private $writers_schema;
- /**
- * @var AvroSchema
- */
- private $readers_schema;
-
- public function __construct(?AvroSchema $writers_schema = null, ?AvroSchema $readers_schema = null)
- {
- $this->writers_schema = $writers_schema;
- $this->readers_schema = $readers_schema;
+ public function __construct(
+ private ?AvroSchema $writers_schema = null,
+ private ?AvroSchema $readers_schema = null
+ ) {
}
public function setWritersSchema(AvroSchema $readers_schema): void
@@ -56,15 +55,12 @@ public function setWritersSchema(AvroSchema $readers_schema): void
$this->writers_schema = $readers_schema;
}
- /**
- * @param AvroIOBinaryDecoder $decoder
- * @returns string
- */
- public function read($decoder)
+ public function read(AvroIOBinaryDecoder $decoder): mixed
{
if (is_null($this->readers_schema)) {
$this->readers_schema = $this->writers_schema;
}
+
return $this->readData(
$this->writers_schema,
$this->readers_schema,
@@ -72,14 +68,15 @@ public function read($decoder)
);
}
- /**
- * @returns mixed
- */
- public function readData(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
+ public function readData(
+ AvroSchema $writers_schema,
+ AvroSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): mixed {
// Schema resolution: reader's schema is a union, writer's schema is not
if (
- AvroSchema::UNION_SCHEMA === $readers_schema->type()
+ $readers_schema instanceof AvroUnionSchema
+ && AvroSchema::UNION_SCHEMA === $readers_schema->type()
&& AvroSchema::UNION_SCHEMA !== $writers_schema->type()
) {
foreach ($readers_schema->schemas() as $schema) {
@@ -90,53 +87,39 @@ public function readData(AvroSchema $writers_schema, AvroSchema $readers_schema,
throw new AvroIOSchemaMatchException($writers_schema, $readers_schema);
}
- switch ($writers_schema->type()) {
- case AvroSchema::NULL_TYPE:
- return $decoder->readNull();
- case AvroSchema::BOOLEAN_TYPE:
- return $decoder->readBoolean();
- case AvroSchema::INT_TYPE:
- return $decoder->readInt();
- case AvroSchema::LONG_TYPE:
- return $decoder->readLong();
- case AvroSchema::FLOAT_TYPE:
- return $decoder->readFloat();
- case AvroSchema::DOUBLE_TYPE:
- return $decoder->readDouble();
- case AvroSchema::STRING_TYPE:
- return $decoder->readString();
- case AvroSchema::BYTES_TYPE:
- $bytes = $decoder->readBytes();
- return $this->readBytes($writers_schema, $readers_schema, $bytes);
- case AvroSchema::ARRAY_SCHEMA:
- return $this->readArray($writers_schema, $readers_schema, $decoder);
- case AvroSchema::MAP_SCHEMA:
- return $this->readMap($writers_schema, $readers_schema, $decoder);
- case AvroSchema::UNION_SCHEMA:
- return $this->readUnion($writers_schema, $readers_schema, $decoder);
- case AvroSchema::ENUM_SCHEMA:
- return $this->readEnum($writers_schema, $readers_schema, $decoder);
- case AvroSchema::FIXED_SCHEMA:
- return $this->readFixed($writers_schema, $readers_schema, $decoder);
- case AvroSchema::RECORD_SCHEMA:
- case AvroSchema::ERROR_SCHEMA:
- case AvroSchema::REQUEST_SCHEMA:
- return $this->readRecord($writers_schema, $readers_schema, $decoder);
- default:
- throw new AvroException(sprintf(
- "Cannot read unknown schema type: %s",
- $writers_schema->type()
- ));
- }
+ return match ($writers_schema->type()) {
+ AvroSchema::NULL_TYPE => $decoder->readNull(),
+ AvroSchema::BOOLEAN_TYPE => $decoder->readBoolean(),
+ AvroSchema::INT_TYPE => $decoder->readInt(),
+ AvroSchema::LONG_TYPE => $decoder->readLong(),
+ AvroSchema::FLOAT_TYPE => $decoder->readFloat(),
+ AvroSchema::DOUBLE_TYPE => $decoder->readDouble(),
+ AvroSchema::STRING_TYPE => $decoder->readString(),
+ AvroSchema::BYTES_TYPE => $this->readBytes($writers_schema, $readers_schema, $decoder->readBytes()),
+ AvroSchema::ARRAY_SCHEMA => $this->readArray($writers_schema, $readers_schema, $decoder),
+ AvroSchema::MAP_SCHEMA => $this->readMap($writers_schema, $readers_schema, $decoder),
+ AvroSchema::UNION_SCHEMA => $this->readUnion($writers_schema, $readers_schema, $decoder),
+ AvroSchema::ENUM_SCHEMA => $this->readEnum($writers_schema, $readers_schema, $decoder),
+ AvroSchema::FIXED_SCHEMA => $this->readFixed($writers_schema, $readers_schema, $decoder),
+ AvroSchema::RECORD_SCHEMA,
+ AvroSchema::ERROR_SCHEMA,
+ AvroSchema::REQUEST_SCHEMA => $this->readRecord($writers_schema, $readers_schema, $decoder),
+ default => throw new AvroException(sprintf(
+ "Cannot read unknown schema type: %s",
+ $writers_schema->type()
+ )),
+ };
}
/**
- *
- * @returns boolean true if the schemas are consistent with
+ * @return bool true if the schemas are consistent with
* each other and false otherwise.
+ * @throws AvroSchemaParseException
*/
- public static function schemasMatch(AvroSchema $writers_schema, AvroSchema $readers_schema)
- {
+ public static function schemasMatch(
+ AvroSchema $writers_schema,
+ AvroSchema $readers_schema
+ ): bool {
$writers_schema_type = $writers_schema->type;
$readers_schema_type = $readers_schema->type;
@@ -150,12 +133,24 @@ public static function schemasMatch(AvroSchema $writers_schema, AvroSchema $read
switch ($readers_schema_type) {
case AvroSchema::MAP_SCHEMA:
+ if (
+ !$writers_schema instanceof AvroMapSchema
+ || !$readers_schema instanceof AvroMapSchema
+ ) {
+ return false;
+ }
return self::attributesMatch(
$writers_schema->values(),
$readers_schema->values(),
[AvroSchema::TYPE_ATTR]
);
case AvroSchema::ARRAY_SCHEMA:
+ if (
+ !$writers_schema instanceof AvroArraySchema
+ || !$readers_schema instanceof AvroArraySchema
+ ) {
+ return false;
+ }
return self::attributesMatch(
$writers_schema->items(),
$readers_schema->items(),
@@ -219,28 +214,37 @@ public static function schemasMatch(AvroSchema $writers_schema, AvroSchema $read
* @param AvroSchema $schema_two
* @param string[] $attribute_names array of string attribute names to compare
*
- * @return boolean true if the attributes match and false otherwise.
+ * @return bool true if the attributes match and false otherwise.
+ * @throws AvroSchemaParseException
*/
- public static function attributesMatch($schema_one, $schema_two, $attribute_names)
- {
+ public static function attributesMatch(
+ AvroSchema $schema_one,
+ AvroSchema $schema_two,
+ array $attribute_names
+ ): bool {
foreach ($attribute_names as $attribute_name) {
- if ($schema_one->attribute($attribute_name) !== $schema_two->attribute($attribute_name)) {
- if ($attribute_name === AvroSchema::FULLNAME_ATTR) {
- foreach ($schema_two->getAliases() as $alias) {
- if (
- $schema_one->attribute($attribute_name) === (new AvroName(
- $alias,
- $schema_two->attribute(AvroSchema::NAMESPACE_ATTR),
- null
- ))->fullname()
- ) {
- return true;
- }
+ if ($schema_one->attribute($attribute_name) === $schema_two->attribute($attribute_name)) {
+ continue;
+ }
+
+ if (AvroSchema::FULLNAME_ATTR === $attribute_name) {
+ if (!$schema_two instanceof AvroAliasedSchema) {
+ return false;
+ }
+ foreach ($schema_two->getAliases() as $alias) {
+ if (
+ $schema_one->attribute($attribute_name) !== (new AvroName(
+ $alias,
+ $schema_two->attribute(AvroSchema::NAMESPACE_ATTR),
+ null
+ ))->fullname()
+ ) {
+ return false;
}
}
- return false;
}
}
+
return true;
}
@@ -262,17 +266,17 @@ public function readBytes(AvroSchema $writers_schema, AvroSchema $readers_schema
return $bytes;
}
- /**
- * @return array
- */
- public function readArray(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
- $items = array();
+ public function readArray(
+ AvroArraySchema $writers_schema,
+ AvroArraySchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): array {
+ $items = [];
$block_count = $decoder->readLong();
while (0 !== $block_count) {
if ($block_count < 0) {
$block_count = -$block_count;
- $block_size = $decoder->readLong(); // Read (and ignore) block size
+ $decoder->readLong(); // Read (and ignore) block size
}
for ($i = 0; $i < $block_count; $i++) {
$items [] = $this->readData(
@@ -283,21 +287,25 @@ public function readArray(AvroSchema $writers_schema, AvroSchema $readers_schema
}
$block_count = $decoder->readLong();
}
+
return $items;
}
/**
- * @returns array
+ * @returns array
*/
- public function readMap(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
- $items = array();
+ public function readMap(
+ AvroMapSchema $writers_schema,
+ AvroMapSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): array {
+ $items = [];
$pair_count = $decoder->readLong();
while (0 != $pair_count) {
if ($pair_count < 0) {
$pair_count = -$pair_count;
// Note: we're not doing anything with block_size other than skipping it
- $block_size = $decoder->readLong();
+ $decoder->readLong();
}
for ($i = 0; $i < $pair_count; $i++) {
@@ -313,34 +321,36 @@ public function readMap(AvroSchema $writers_schema, AvroSchema $readers_schema,
return $items;
}
- /**
- * @returns mixed
- */
- public function readUnion(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
+ public function readUnion(
+ AvroUnionSchema $writers_schema,
+ AvroUnionSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): mixed {
$schema_index = $decoder->readLong();
$selected_writers_schema = $writers_schema->schemaByIndex($schema_index);
return $this->readData($selected_writers_schema, $readers_schema, $decoder);
}
- /**
- * @returns string
- */
- public function readEnum(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
+ public function readEnum(
+ AvroEnumSchema $writers_schema,
+ AvroEnumSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): ?string {
$symbol_index = $decoder->readInt();
$symbol = $writers_schema->symbolByIndex($symbol_index);
+
if (!$readers_schema->hasSymbol($symbol)) {
- null;
+ return null;
} // FIXME: unset wrt schema resolution
+
return $symbol;
}
- /**
- * @returns string|AvroDuration
- */
- public function readFixed(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
+ public function readFixed(
+ AvroFixedSchema $writers_schema,
+ AvroFixedSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): string|AvroDuration {
$logicalTypeWriters = $writers_schema->logicalType();
if ($logicalTypeWriters instanceof AvroLogicalType) {
if ($logicalTypeWriters !== $readers_schema->logicalType()) {
@@ -358,6 +368,8 @@ public function readFixed(AvroSchema $writers_schema, AvroSchema $readers_schema
}
return AvroDuration::fromBytes($encodedDuration);
+ default:
+ throw new AvroException('Unknown logical type for fixed: ' . $logicalTypeWriters->name());
}
}
@@ -367,8 +379,11 @@ public function readFixed(AvroSchema $writers_schema, AvroSchema $readers_schema
/**
* @returns array
*/
- public function readRecord(AvroSchema $writers_schema, AvroSchema $readers_schema, AvroIOBinaryDecoder $decoder)
- {
+ public function readRecord(
+ AvroRecordSchema $writers_schema,
+ AvroRecordSchema $readers_schema,
+ AvroIOBinaryDecoder $decoder
+ ) {
$readers_fields = $readers_schema->fieldsHash();
$record = [];
foreach ($writers_schema->fields() as $writers_field) {
@@ -392,66 +407,45 @@ public function readRecord(AvroSchema $writers_schema, AvroSchema $readers_schem
}
if ($field->hasDefaultValue()) {
$record[$field->name()] = $this->readDefaultValue($field->type(), $field->defaultValue());
- } else {
- null;
}
}
return $record;
}
- /**
- * @param AvroSchema $writers_schema
- * @param AvroIOBinaryDecoder $decoder
- */
- public static function skipData($writers_schema, $decoder)
- {
- switch ($writers_schema->type()) {
- case AvroSchema::NULL_TYPE:
- return $decoder->skipNull();
- case AvroSchema::BOOLEAN_TYPE:
- return $decoder->skipBoolean();
- case AvroSchema::INT_TYPE:
- return $decoder->skipInt();
- case AvroSchema::LONG_TYPE:
- return $decoder->skipLong();
- case AvroSchema::FLOAT_TYPE:
- return $decoder->skipFloat();
- case AvroSchema::DOUBLE_TYPE:
- return $decoder->skipDouble();
- case AvroSchema::STRING_TYPE:
- return $decoder->skipString();
- case AvroSchema::BYTES_TYPE:
- return $decoder->skipBytes();
- case AvroSchema::ARRAY_SCHEMA:
- return $decoder->skipArray($writers_schema, $decoder);
- case AvroSchema::MAP_SCHEMA:
- return $decoder->skipMap($writers_schema, $decoder);
- case AvroSchema::UNION_SCHEMA:
- return $decoder->skipUnion($writers_schema, $decoder);
- case AvroSchema::ENUM_SCHEMA:
- return $decoder->skipEnum($writers_schema, $decoder);
- case AvroSchema::FIXED_SCHEMA:
- return $decoder->skipFixed($writers_schema, $decoder);
- case AvroSchema::RECORD_SCHEMA:
- case AvroSchema::ERROR_SCHEMA:
- case AvroSchema::REQUEST_SCHEMA:
- return $decoder->skipRecord($writers_schema, $decoder);
- default:
- throw new AvroException(sprintf(
- 'Unknown schema type: %s',
- $writers_schema->type()
- ));
- }
+ public static function skipData(
+ AvroSchema|AvroFixedSchema|AvroEnumSchema|AvroUnionSchema|AvroArraySchema|AvroMapSchema $writers_schema,
+ AvroIOBinaryDecoder $decoder
+ ): void {
+ match ($writers_schema->type()) {
+ AvroSchema::NULL_TYPE => $decoder->skipNull(),
+ AvroSchema::BOOLEAN_TYPE => $decoder->skipBoolean(),
+ AvroSchema::INT_TYPE => $decoder->skipInt(),
+ AvroSchema::LONG_TYPE => $decoder->skipLong(),
+ AvroSchema::FLOAT_TYPE => $decoder->skipFloat(),
+ AvroSchema::DOUBLE_TYPE => $decoder->skipDouble(),
+ AvroSchema::STRING_TYPE => $decoder->skipString(),
+ AvroSchema::BYTES_TYPE => $decoder->skipBytes(),
+ AvroSchema::ARRAY_SCHEMA => $decoder->skipArray($writers_schema, $decoder),
+ AvroSchema::MAP_SCHEMA => $decoder->skipMap($writers_schema, $decoder),
+ AvroSchema::UNION_SCHEMA => $decoder->skipUnion($writers_schema, $decoder),
+ AvroSchema::ENUM_SCHEMA => $decoder->skipEnum($writers_schema, $decoder),
+ AvroSchema::FIXED_SCHEMA => $decoder->skipFixed($writers_schema, $decoder),
+ AvroSchema::RECORD_SCHEMA, AvroSchema::ERROR_SCHEMA, AvroSchema::REQUEST_SCHEMA => $decoder->skipRecord($writers_schema, $decoder),
+ default => throw new AvroException(sprintf(
+ 'Unknown schema type: %s',
+ $writers_schema->type()
+ )),
+ };
}
/**
* @param null|boolean|int|float|string|array $default_value
- * @returns null|boolean|int|float|string|array
+ * @return null|boolean|int|float|string|array
*
* @throws AvroException if $field_schema type is unknown.
*/
- public function readDefaultValue(AvroSchema $field_schema, $default_value)
+ public function readDefaultValue(AvroSchema $field_schema, mixed $default_value): mixed
{
switch ($field_schema->type()) {
case AvroSchema::NULL_TYPE:
@@ -468,16 +462,18 @@ public function readDefaultValue(AvroSchema $field_schema, $default_value)
case AvroSchema::BYTES_TYPE:
return $this->readBytes($field_schema, $field_schema, $default_value);
case AvroSchema::ARRAY_SCHEMA:
- $array = array();
+ $array = [];
foreach ($default_value as $json_val) {
+ /** @phpstan-ignore method.notFound */
$val = $this->readDefaultValue($field_schema->items(), $json_val);
$array [] = $val;
}
return $array;
case AvroSchema::MAP_SCHEMA:
- $map = array();
+ $map = [];
foreach ($default_value as $key => $json_val) {
$map[$key] = $this->readDefaultValue(
+ /** @phpstan-ignore method.notFound */
$field_schema->values(),
$json_val
);
@@ -485,6 +481,7 @@ public function readDefaultValue(AvroSchema $field_schema, $default_value)
return $map;
case AvroSchema::UNION_SCHEMA:
return $this->readDefaultValue(
+ /** @phpstan-ignore method.notFound */
$field_schema->schemaByIndex(0),
$default_value
);
@@ -492,7 +489,8 @@ public function readDefaultValue(AvroSchema $field_schema, $default_value)
case AvroSchema::FIXED_SCHEMA:
return $default_value;
case AvroSchema::RECORD_SCHEMA:
- $record = array();
+ $record = [];
+ /** @phpstan-ignore method.notFound */
foreach ($field_schema->fields() as $field) {
$field_name = $field->name();
if (!$json_val = $default_value[$field_name]) {
diff --git a/lang/php/lib/Datum/AvroIODatumWriter.php b/lang/php/lib/Datum/AvroIODatumWriter.php
index 13e2bbe3887..638a85d5126 100644
--- a/lang/php/lib/Datum/AvroIODatumWriter.php
+++ b/lang/php/lib/Datum/AvroIODatumWriter.php
@@ -22,9 +22,14 @@
use Apache\Avro\AvroException;
use Apache\Avro\Datum\Type\AvroDuration;
+use Apache\Avro\Schema\AvroArraySchema;
+use Apache\Avro\Schema\AvroEnumSchema;
use Apache\Avro\Schema\AvroLogicalType;
+use Apache\Avro\Schema\AvroMapSchema;
+use Apache\Avro\Schema\AvroRecordSchema;
use Apache\Avro\Schema\AvroSchema;
use Apache\Avro\Schema\AvroSchemaParseException;
+use Apache\Avro\Schema\AvroUnionSchema;
/**
* Handles schema-specific writing of data to the encoder.
@@ -59,7 +64,6 @@ public function write($datum, AvroIOBinaryEncoder $encoder)
* @param AvroSchema $writers_schema
* @param $datum
* @param AvroIOBinaryEncoder $encoder
- * @return mixed
*
* @throws AvroIOTypeException if $datum is invalid for $writers_schema
* @throws AvroException if the type is invalid
@@ -136,7 +140,7 @@ private function writeValidatedData(AvroSchema $writers_schema, $datum, AvroIOBi
}
}
- private function writeBytes(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeBytes(AvroSchema $writers_schema, string $datum, AvroIOBinaryEncoder $encoder): void
{
$logicalType = $writers_schema->logicalType();
if (
@@ -154,10 +158,9 @@ private function writeBytes(AvroSchema $writers_schema, $datum, AvroIOBinaryEnco
}
/**
- * @param null|boolean|int|float|string|array $datum item to be written
* @throws AvroIOTypeException
*/
- private function writeArray(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeArray(AvroArraySchema $writers_schema, array $datum, AvroIOBinaryEncoder $encoder): void
{
$datum_count = count($datum);
if (0 < $datum_count) {
@@ -171,10 +174,9 @@ private function writeArray(AvroSchema $writers_schema, $datum, AvroIOBinaryEnco
}
/**
- * @param $datum
* @throws AvroIOTypeException
*/
- private function writeMap(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeMap(AvroMapSchema $writers_schema, array $datum, AvroIOBinaryEncoder $encoder): void
{
$datum_count = count($datum);
if ($datum_count > 0) {
@@ -187,8 +189,11 @@ private function writeMap(AvroSchema $writers_schema, $datum, AvroIOBinaryEncode
$encoder->writeLong(0);
}
- private function writeFixed(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
- {
+ private function writeFixed(
+ AvroSchema $writers_schema,
+ string|AvroDuration $datum,
+ AvroIOBinaryEncoder $encoder
+ ): void {
$logicalType = $writers_schema->logicalType();
if (
$logicalType instanceof AvroLogicalType
@@ -222,13 +227,13 @@ private function writeFixed(AvroSchema $writers_schema, $datum, AvroIOBinaryEnco
$encoder->write($datum);
}
- private function writeEnum(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeEnum(AvroEnumSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
{
$datum_index = $writers_schema->symbolIndex($datum);
$encoder->writeInt($datum_index);
}
- private function writeRecord(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeRecord(AvroRecordSchema $writers_schema, mixed $datum, AvroIOBinaryEncoder $encoder): void
{
foreach ($writers_schema->fields() as $field) {
$this->writeValidatedData($field->type(), $datum[$field->name()] ?? null, $encoder);
@@ -239,7 +244,7 @@ private function writeRecord(AvroSchema $writers_schema, $datum, AvroIOBinaryEnc
* @throws AvroIOTypeException
* @throws AvroSchemaParseException
*/
- private function writeUnion(AvroSchema $writers_schema, $datum, AvroIOBinaryEncoder $encoder): void
+ private function writeUnion(AvroUnionSchema $writers_schema, mixed $datum, AvroIOBinaryEncoder $encoder): void
{
$datum_schema_index = -1;
$datum_schema = null;
diff --git a/lang/php/lib/Datum/Type/AvroDuration.php b/lang/php/lib/Datum/Type/AvroDuration.php
index 7bf40d4a118..369a8d6a490 100644
--- a/lang/php/lib/Datum/Type/AvroDuration.php
+++ b/lang/php/lib/Datum/Type/AvroDuration.php
@@ -25,16 +25,13 @@
use Apache\Avro\AvroException;
use Apache\Avro\Schema\AvroSchema;
-class AvroDuration
+class AvroDuration implements \Stringable
{
- /** @var int */
- private $months;
+ private readonly int $months;
- /** @var int */
- private $days;
+ private readonly int $days;
- /** @var int */
- private $milliseconds;
+ private readonly int $milliseconds;
/**
* @throws AvroException
diff --git a/lang/php/lib/IO/AvroFile.php b/lang/php/lib/IO/AvroFile.php
index b68de63eed1..687896b0ed9 100644
--- a/lang/php/lib/IO/AvroFile.php
+++ b/lang/php/lib/IO/AvroFile.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\IO;
use Apache\Avro\AvroIO;
@@ -26,7 +28,7 @@
* AvroIO wrapper for PHP file access functions
* @package Avro
*/
-class AvroFile extends AvroIO
+class AvroFile implements AvroIO
{
/**
* @var string fopen read mode value. Used internally.
@@ -38,33 +40,25 @@ class AvroFile extends AvroIO
*/
public const FOPEN_WRITE_MODE = 'wb';
- /**
- * @var string
- */
- private $file_path;
-
/**
* @var resource file handle for AvroFile instance
*/
private $file_handle;
- public function __construct($file_path, $mode = self::READ_MODE)
- {
- /**
- * XXX: should we check for file existence (in case of reading)
- * or anything else about the provided file_path argument?
- */
- $this->file_path = $file_path;
+ public function __construct(
+ private string $file_path,
+ string $mode = self::READ_MODE
+ ) {
switch ($mode) {
case self::WRITE_MODE:
$this->file_handle = fopen($this->file_path, self::FOPEN_WRITE_MODE);
- if (false == $this->file_handle) {
+ if (false === $this->file_handle) {
throw new AvroIOException('Could not open file for writing');
}
break;
case self::READ_MODE:
$this->file_handle = fopen($this->file_path, self::FOPEN_READ_MODE);
- if (false == $this->file_handle) {
+ if (false === $this->file_handle) {
throw new AvroIOException('Could not open file for reading');
}
break;
@@ -81,12 +75,12 @@ public function __construct($file_path, $mode = self::READ_MODE)
}
/**
- * @returns int count of bytes written
+ * @return int count of bytes written
* @throws AvroIOException if write failed.
*/
- public function write($str)
+ public function write(string $bytes): int
{
- $len = fwrite($this->file_handle, $str);
+ $len = fwrite($this->file_handle, $bytes);
if (false === $len) {
throw new AvroIOException(sprintf('Could not write to file'));
}
@@ -97,7 +91,7 @@ public function write($str)
* @returns int current position within the file
* @throws AvroIOException if tell failed.
*/
- public function tell()
+ public function tell(): int
{
$position = ftell($this->file_handle);
if (false === $position) {
@@ -108,10 +102,10 @@ public function tell()
/**
* Closes the file.
- * @returns boolean true if successful.
+ * @returns bool true if successful.
* @throws AvroIOException if there was an error closing the file.
*/
- public function close()
+ public function close(): bool
{
$res = fclose($this->file_handle);
if (false === $res) {
@@ -125,7 +119,7 @@ public function close()
* and false otherwise.
* @see AvroIO::isEof() as behavior differs from feof()
*/
- public function isEof()
+ public function isEof(): bool
{
$this->read(1);
if (feof($this->file_handle)) {
@@ -140,7 +134,7 @@ public function isEof()
* @returns string bytes read
* @throws AvroIOException if length value is negative or if the read failed
*/
- public function read($len)
+ public function read(int $len): string
{
if (0 > $len) {
throw new AvroIOException(
@@ -148,7 +142,7 @@ public function read($len)
);
}
- if (0 == $len) {
+ if (0 === $len) {
return '';
}
@@ -166,7 +160,7 @@ public function read($len)
* @throws AvroIOException if seek failed.
* @see AvroIO::seek()
*/
- public function seek($offset, $whence = SEEK_SET): bool
+ public function seek(int $offset, int $whence = SEEK_SET): bool
{
$res = fseek($this->file_handle, $offset, $whence);
// Note: does not catch seeking beyond end of file
@@ -186,7 +180,7 @@ public function seek($offset, $whence = SEEK_SET): bool
* @returns boolean true if the flush was successful.
* @throws AvroIOException if there was an error flushing the file.
*/
- public function flush()
+ public function flush(): bool
{
$res = fflush($this->file_handle);
if (false === $res) {
diff --git a/lang/php/lib/IO/AvroStringIO.php b/lang/php/lib/IO/AvroStringIO.php
index 9b98ff31c2e..9e3288bd6fb 100644
--- a/lang/php/lib/IO/AvroStringIO.php
+++ b/lang/php/lib/IO/AvroStringIO.php
@@ -18,6 +18,8 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\IO;
use Apache\Avro\AvroIO;
@@ -26,20 +28,20 @@
* AvroIO wrapper for string access
* @package Avro
*/
-class AvroStringIO extends AvroIO
+class AvroStringIO implements AvroIO, \Stringable
{
/**
* @var string
*/
- private $string_buffer;
+ private string $string_buffer;
/**
* @var int current position in string
*/
- private $current_index;
+ private int $current_index;
/**
- * @var boolean whether or not the string is closed.
+ * @var bool whether or not the string is closed.
*/
- private $is_closed;
+ private bool $is_closed;
/**
* @param string $str initial value of AvroStringIO buffer. Regardless
@@ -47,7 +49,7 @@ class AvroStringIO extends AvroIO
* beginning of the buffer.
* @throws AvroIOException if a non-string value is passed as $str
*/
- public function __construct($str = '')
+ public function __construct(string $str = '')
{
$this->is_closed = false;
$this->string_buffer = '';
@@ -65,21 +67,21 @@ public function __construct($str = '')
/**
* Append bytes to this buffer.
* (Nothing more is needed to support Avro.)
- * @param string $arg bytes to write
+ * @param string $bytes bytes to write
* @returns int count of bytes written.
* @throws AvroIOException if $args is not a string value.
*/
- public function write($arg)
+ public function write(string $bytes): int
{
$this->checkClosed();
- if (is_string($arg)) {
- return $this->appendStr($arg);
+ if (is_string($bytes)) {
+ return $this->appendStr($bytes);
}
throw new AvroIOException(
sprintf(
'write argument must be a string: (%s) %s',
- gettype($arg),
- var_export($arg, true)
+ gettype($bytes),
+ var_export($bytes, true)
)
);
}
@@ -87,7 +89,7 @@ public function write($arg)
/**
* @throws AvroIOException if the buffer is closed.
*/
- private function checkClosed()
+ private function checkClosed(): void
{
if ($this->isClosed()) {
throw new AvroIOException('Buffer is closed');
@@ -95,10 +97,9 @@ private function checkClosed()
}
/**
- * @returns boolean true if this buffer is closed and false
- * otherwise.
+ * @return bool true if this buffer is closed and false otherwise.
*/
- public function isClosed()
+ public function isClosed(): bool
{
return $this->is_closed;
}
@@ -106,9 +107,10 @@ public function isClosed()
/**
* Appends bytes to this buffer.
* @param string $str
- * @returns integer count of bytes written.
+ * @return int count of bytes written.
+ * @throws AvroIOException
*/
- private function appendStr($str)
+ private function appendStr(string $str): int
{
$this->checkClosed();
$this->string_buffer .= $str;
@@ -121,7 +123,7 @@ private function appendStr($str)
* @returns string bytes read from buffer
* @todo test for fencepost errors wrt updating current_index
*/
- public function read($len)
+ public function read($len): string
{
$this->checkClosed();
$read = '';
@@ -141,7 +143,7 @@ public function read($len)
* @internal Could probably memoize length for performance, but
* no need do this yet.
*/
- public function length()
+ public function length(): int
{
return strlen($this->string_buffer);
}
@@ -183,37 +185,34 @@ public function seek($offset, $whence = self::SEEK_SET): bool
}
/**
- * @returns int
* @see AvroIO::tell()
*/
- public function tell()
+ public function tell(): int
{
return $this->current_index;
}
/**
- * @returns boolean
* @see AvroIO::isEof()
*/
- public function isEof()
+ public function isEof(): bool
{
return ($this->current_index >= $this->length());
}
/**
* No-op provided for compatibility with AvroIO interface.
- * @returns boolean true
+ * @returns bool true
*/
- public function flush()
+ public function flush(): bool
{
return true;
}
/**
* Marks this buffer as closed.
- * @returns boolean true
*/
- public function close()
+ public function close(): bool
{
$this->checkClosed();
$this->is_closed = true;
@@ -223,9 +222,9 @@ public function close()
/**
* Truncates the truncate buffer to 0 bytes and returns the pointer
* to the beginning of the buffer.
- * @returns boolean true
+ * @returns bool true
*/
- public function truncate()
+ public function truncate(): bool
{
$this->checkClosed();
$this->string_buffer = '';
@@ -237,7 +236,7 @@ public function truncate()
* @returns string
* @uses self::__toString()
*/
- public function string()
+ public function string(): string
{
return (string) $this;
}
@@ -245,7 +244,7 @@ public function string()
/**
* @returns string
*/
- public function __toString()
+ public function __toString(): string
{
return $this->string_buffer;
}
diff --git a/lang/php/lib/Protocol/AvroProtocol.php b/lang/php/lib/Protocol/AvroProtocol.php
index a1be7b79bf5..ae0ec3538b2 100644
--- a/lang/php/lib/Protocol/AvroProtocol.php
+++ b/lang/php/lib/Protocol/AvroProtocol.php
@@ -18,10 +18,13 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\Protocol;
use Apache\Avro\Schema\AvroNamedSchemata;
use Apache\Avro\Schema\AvroSchema;
+use Apache\Avro\Schema\AvroSchemaParseException;
/**
* Avro library for protocols
@@ -29,39 +32,64 @@
*/
class AvroProtocol
{
- public $protocol;
- public $name;
- public $namespace;
- public $schemata;
- public $messages;
+ public function __construct(
+ public readonly string $protocol,
+ public readonly string $name,
+ public readonly string $namespace,
+ public readonly AvroNamedSchemata $schemata,
+ /** @var array */
+ public readonly array $messages,
+ ) {
+ }
- public static function parse($json)
+ /**
+ * @throws AvroProtocolParseException
+ * @throws AvroSchemaParseException
+ */
+ public static function parse(string $json): self
{
- if (is_null($json)) {
- throw new AvroProtocolParseException("Protocol can't be null");
+ try {
+ return self::realParse(
+ json_decode($json, associative: true, flags: JSON_THROW_ON_ERROR)
+ );
+ } catch (\JsonException $e) {
+ throw new AvroProtocolParseException(
+ "Protocol json schema is invalid: ".$e->getMessage(),
+ previous: $e
+ );
}
-
- $protocol = new AvroProtocol();
- $protocol->realParse(json_decode($json, true));
- return $protocol;
}
- public function realParse($avro)
+ /**
+ * @param array $avro AVRO protocol as associative array
+ * @throws AvroSchemaParseException
+ */
+ public static function realParse(array $avro): self
{
- $this->protocol = $avro["protocol"];
- $this->namespace = $avro["namespace"];
- $this->schemata = new AvroNamedSchemata();
- $this->name = $avro["protocol"];
+ $schemata = new AvroNamedSchemata();
if (!is_null($avro["types"])) {
- $types = AvroSchema::realParse($avro["types"], $this->namespace, $this->schemata);
+ AvroSchema::realParse($avro["types"], $avro["namespace"], $schemata);
}
+ $messages = [];
if (!is_null($avro["messages"])) {
foreach ($avro["messages"] as $messageName => $messageAvro) {
- $message = new AvroProtocolMessage($messageName, $messageAvro, $this);
- $this->messages[$messageName] = $message;
+ $messages[] = new AvroProtocolMessage(
+ name: $messageName,
+ avro: $messageAvro,
+ namespace: $avro["namespace"],
+ schemata: $schemata
+ );
}
}
+
+ return new self(
+ protocol: $avro["protocol"],
+ name: $avro["protocol"],
+ namespace: $avro["namespace"],
+ schemata: $schemata,
+ messages: $messages
+ );
}
}
diff --git a/lang/php/lib/Protocol/AvroProtocolMessage.php b/lang/php/lib/Protocol/AvroProtocolMessage.php
index 186e3ce5e8f..9677591dd2b 100644
--- a/lang/php/lib/Protocol/AvroProtocolMessage.php
+++ b/lang/php/lib/Protocol/AvroProtocolMessage.php
@@ -18,44 +18,54 @@
* limitations under the License.
*/
+declare(strict_types=1);
+
namespace Apache\Avro\Protocol;
use Apache\Avro\Schema\AvroName;
+use Apache\Avro\Schema\AvroNamedSchemata;
use Apache\Avro\Schema\AvroPrimitiveSchema;
use Apache\Avro\Schema\AvroRecordSchema;
use Apache\Avro\Schema\AvroSchema;
+use Apache\Avro\Schema\AvroSchemaParseException;
class AvroProtocolMessage
{
- public $name;
+ public readonly AvroRecordSchema $request;
+
+ public readonly ?AvroSchema $response;
/**
- * @var AvroRecordSchema $request
+ * @throws AvroSchemaParseException
*/
- public $request;
-
- public $response;
-
- public function __construct($name, $avro, $protocol)
- {
- $this->name = $name;
+ public function __construct(
+ public string $name,
+ array $avro,
+ string $namespace,
+ AvroNamedSchemata $schemata,
+ ) {
$this->request = new AvroRecordSchema(
- new AvroName($name, null, $protocol->namespace),
- null,
- $avro['request'],
- $protocol->schemata,
- AvroSchema::REQUEST_SCHEMA
+ name: new AvroName($this->name, null, $namespace),
+ doc: null,
+ fields: $avro['request'],
+ schemata: $schemata,
+ schema_type: AvroSchema::REQUEST_SCHEMA
);
+ $response = null;
if (array_key_exists('response', $avro)) {
- $this->response = $protocol->schemata->schemaByName(new AvroName(
- $avro['response'],
- $protocol->namespace,
- $protocol->namespace
- ));
- if ($this->response == null) {
- $this->response = new AvroPrimitiveSchema($avro['response']);
+ $response = $schemata->schemaByName(
+ new AvroName(
+ name: $avro['response'],
+ namespace: $namespace,
+ default_namespace: $namespace
+ )
+ );
+
+ if (is_null($response)) {
+ $response = new AvroPrimitiveSchema($avro['response']);
}
}
+ $this->response = $response;
}
}
diff --git a/lang/php/lib/Schema/AvroAliasedSchema.php b/lang/php/lib/Schema/AvroAliasedSchema.php
new file mode 100644
index 00000000000..13ca0a638d4
--- /dev/null
+++ b/lang/php/lib/Schema/AvroAliasedSchema.php
@@ -0,0 +1,28 @@
+items;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
$avro[AvroSchema::ITEMS_ATTR] = $this->is_items_schema_from_schemata
diff --git a/lang/php/lib/Schema/AvroEnumSchema.php b/lang/php/lib/Schema/AvroEnumSchema.php
index 523fedd39a5..e9f22268e5e 100644
--- a/lang/php/lib/Schema/AvroEnumSchema.php
+++ b/lang/php/lib/Schema/AvroEnumSchema.php
@@ -107,10 +107,7 @@ public function symbolIndex($symbol)
throw new AvroException(sprintf("Invalid symbol value '%s'", $symbol));
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
$avro[AvroSchema::SYMBOLS_ATTR] = $this->symbols;
diff --git a/lang/php/lib/Schema/AvroField.php b/lang/php/lib/Schema/AvroField.php
index eeb50bc197d..e177eb774ae 100644
--- a/lang/php/lib/Schema/AvroField.php
+++ b/lang/php/lib/Schema/AvroField.php
@@ -24,7 +24,7 @@
* Field of an {@link AvroRecordSchema}
* @package Avro
*/
-class AvroField extends AvroSchema
+class AvroField extends AvroSchema implements AvroAliasedSchema
{
/**
* @var string fields name attribute name
@@ -59,66 +59,55 @@ class AvroField extends AvroSchema
/**
* @var array list of valid field sort order values
*/
- private static $validFieldSortOrders = array(
+ private static array $validFieldSortOrders = [
self::ASC_SORT_ORDER,
self::DESC_SORT_ORDER,
self::IGNORE_SORT_ORDER
- );
- /**
- * @var string
- */
- private $name;
+ ];
+
+ private ?string $name;
+
+ private bool $isTypeFromSchemata;
+
/**
- * @var boolean whether or no there is a default value
+ * @var bool whether or no there is a default value
*/
- private $hasDefault;
+ private bool $hasDefault;
+
/**
* @var string field default value
*/
- private $default;
+ private mixed $default;
/**
- * @var string sort order of this field
+ * @var null|string sort order of this field
*/
- private $order;
- /**
- * @var boolean whether or not the AvroNamedSchema of this field is
- * defined in the AvroNamedSchemata instance
- */
- private $isTypeFromSchemata;
+ private ?string $order;
/**
* @var array|null
*/
- private $aliases;
+ private ?array $aliases;
/**
- * @param string $name
- * @param AvroSchema $schema
- * @param boolean $is_type_from_schemata
- * @param $has_default
- * @param string $default
- * @param string $order
- * @param array $aliases
* @throws AvroSchemaParseException
* @todo Check validity of $default value
- * @todo Check validity of $order value
*/
public function __construct(
- $name,
- $schema,
- $is_type_from_schemata,
- $has_default,
- $default,
- $order = null,
- $aliases = null
+ ?string $name,
+ string|AvroSchema $schema,
+ bool $isTypeFromSchemata,
+ bool $hasDefault,
+ mixed $default,
+ ?string $order = null,
+ mixed $aliases = null
) {
if (!AvroName::isWellFormedName($name)) {
throw new AvroSchemaParseException('Field requires a "name" attribute');
}
parent::__construct($schema);
- $this->isTypeFromSchemata = $is_type_from_schemata;
$this->name = $name;
- $this->hasDefault = $has_default;
+ $this->isTypeFromSchemata = $isTypeFromSchemata;
+ $this->hasDefault = $hasDefault;
if ($this->hasDefault) {
$this->default = $default;
}
@@ -129,11 +118,10 @@ public function __construct(
}
/**
- * @param string $order
* @throws AvroSchemaParseException if $order is not a valid
* field order value.
*/
- private static function checkOrderValue($order)
+ private static function checkOrderValue(?string $order): void
{
if (!is_null($order) && !self::isValidFieldSortOrder($order)) {
throw new AvroSchemaParseException(
@@ -142,31 +130,27 @@ private static function checkOrderValue($order)
}
}
- /**
- * @param string $order
- * @returns boolean
- */
- private static function isValidFieldSortOrder($order)
+ private static function isValidFieldSortOrder(string $order): bool
{
- return in_array($order, self::$validFieldSortOrders);
+ return in_array($order, self::$validFieldSortOrders, true);
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
- $avro = array(AvroField::FIELD_NAME_ATTR => $this->name);
+ $avro = [self::FIELD_NAME_ATTR => $this->name];
- $avro[AvroSchema::TYPE_ATTR] = ($this->isTypeFromSchemata)
- ? $this->type->qualifiedName() : $this->type->toAvro();
+ $avro[AvroSchema::TYPE_ATTR] = match (true) {
+ $this->isTypeFromSchemata && $this->type instanceof AvroNamedSchema => $this->type->qualifiedName(),
+ $this->type instanceof AvroSchema => $this->type->toAvro(),
+ is_string($this->type) => $this->type,
+ };
if (isset($this->default)) {
- $avro[AvroField::DEFAULT_ATTR] = $this->default;
+ $avro[self::DEFAULT_ATTR] = $this->default;
}
if ($this->order) {
- $avro[AvroField::ORDER_ATTR] = $this->order;
+ $avro[self::ORDER_ATTR] = $this->order;
}
return $avro;
@@ -196,7 +180,7 @@ public function hasDefaultValue()
return $this->hasDefault;
}
- public function getAliases()
+ public function getAliases(): ?array
{
return $this->aliases;
}
diff --git a/lang/php/lib/Schema/AvroFixedSchema.php b/lang/php/lib/Schema/AvroFixedSchema.php
index a48073ad361..366a83a60eb 100644
--- a/lang/php/lib/Schema/AvroFixedSchema.php
+++ b/lang/php/lib/Schema/AvroFixedSchema.php
@@ -34,36 +34,24 @@ class AvroFixedSchema extends AvroNamedSchema
private $size;
/**
- * @param AvroName $name
- * @param string $doc Set to null, as fixed schemas don't have doc strings
* @param int $size byte count of this fixed schema data value
- * @param AvroNamedSchemata &$schemata
- * @param array $aliases
* @throws AvroSchemaParseException
*/
- public function __construct($name, $doc, $size, &$schemata = null, $aliases = null)
+ public function __construct(AvroName $name, int $size, ?AvroNamedSchemata &$schemata = null, ?array $aliases = null)
{
- if (!is_int($size)) {
- throw new AvroSchemaParseException(
- 'Fixed Schema requires a valid integer for "size" attribute'
- );
- }
parent::__construct(AvroSchema::FIXED_SCHEMA, $name, null, $schemata, $aliases);
$this->size = $size;
}
/**
- * @returns int byte count of this fixed schema data value
+ * @return int byte count of this fixed schema data value
*/
- public function size()
+ public function size(): int
{
return $this->size;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
$avro[AvroSchema::SIZE_ATTR] = $this->size;
@@ -76,11 +64,10 @@ public function toAvro()
*/
public static function duration(
AvroName $name,
- ?string $doc,
- AvroNamedSchemata &$schemata = null,
+ ?AvroNamedSchemata &$schemata = null,
?array $aliases = null
): self {
- $fixedSchema = new self($name, $doc, 12, $schemata, $aliases);
+ $fixedSchema = new self($name, 12, $schemata, $aliases);
$fixedSchema->logicalType = AvroLogicalType::duration();
@@ -94,14 +81,13 @@ public static function duration(
*/
public static function decimal(
AvroName $name,
- ?string $doc,
int $size,
int $precision,
int $scale,
?AvroNamedSchemata &$schemata = null,
?array $aliases = null
): self {
- $self = new self($name, $doc, $size, $schemata, $aliases);
+ $self = new self($name, $size, $schemata, $aliases);
$maxPrecision = (int) floor(log10(self::maxDecimalMagnitude($size)));
diff --git a/lang/php/lib/Schema/AvroLogicalType.php b/lang/php/lib/Schema/AvroLogicalType.php
index 9b19794473a..bb175c608d1 100644
--- a/lang/php/lib/Schema/AvroLogicalType.php
+++ b/lang/php/lib/Schema/AvroLogicalType.php
@@ -27,16 +27,8 @@ class AvroLogicalType
public const ATTRIBUTE_DECIMAL_PRECISION = 'precision';
public const ATTRIBUTE_DECIMAL_SCALE = 'scale';
- /** @var string */
- private $name;
-
- /** @var array */
- private $attributes;
-
- public function __construct(string $name, array $attributes = [])
+ public function __construct(private readonly string $name, private readonly array $attributes = [])
{
- $this->name = $name;
- $this->attributes = $attributes;
}
public function name(): string
@@ -49,7 +41,7 @@ public function attributes(): array
return $this->attributes;
}
- public function toAvro(): array
+ public function toAvro(): string|array
{
$avro[AvroSchema::LOGICAL_TYPE_ATTR] = $this->name;
return array_merge($avro, $this->attributes);
diff --git a/lang/php/lib/Schema/AvroMapSchema.php b/lang/php/lib/Schema/AvroMapSchema.php
index dfcb9dab85f..46ca3e0502a 100644
--- a/lang/php/lib/Schema/AvroMapSchema.php
+++ b/lang/php/lib/Schema/AvroMapSchema.php
@@ -28,24 +28,17 @@
class AvroMapSchema extends AvroSchema
{
/**
- * @var string|AvroSchema named schema name or AvroSchema
- * of map schema values.
+ * AvroSchema definition based on input $values variable that could contain a primitive type or an associative
+ * array with the AVRO definition.
*/
- private $values;
+ private AvroSchema $values;
/**
- * @var boolean true if the named schema
- * XXX Couldn't we derive this based on whether or not
- * $this->values is a string?
+ * @var bool true if the named schema
*/
- private $isValuesSchemaFromSchemata;
+ private bool $isValuesSchemaFromSchemata;
- /**
- * @param string|AvroSchema $values
- * @param string $defaultNamespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata
- */
- public function __construct($values, $defaultNamespace, &$schemata = null)
+ public function __construct(string|array $values, ?string $defaultNamespace, ?AvroNamedSchemata &$schemata = null)
{
parent::__construct(AvroSchema::MAP_SCHEMA);
@@ -69,22 +62,18 @@ public function __construct($values, $defaultNamespace, &$schemata = null)
$this->values = $values_schema;
}
- /**
- * @returns XXX|AvroSchema
- */
- public function values()
+ public function values(): AvroSchema
{
return $this->values;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
- $avro[AvroSchema::VALUES_ATTR] = $this->isValuesSchemaFromSchemata
- ? $this->values->qualifiedName() : $this->values->toAvro();
+ $avro[AvroSchema::VALUES_ATTR] = match (true) {
+ $this->isValuesSchemaFromSchemata && $this->values instanceof AvroNamedSchema => $this->values->qualifiedName(),
+ default => $this->values->toAvro(),
+ };
return $avro;
}
}
diff --git a/lang/php/lib/Schema/AvroName.php b/lang/php/lib/Schema/AvroName.php
index 19ddd06972d..ae34fffc573 100644
--- a/lang/php/lib/Schema/AvroName.php
+++ b/lang/php/lib/Schema/AvroName.php
@@ -23,7 +23,7 @@
/**
* @package Avro
*/
-class AvroName
+class AvroName implements \Stringable
{
/**
* @var string character used to separate names comprising the fullname
@@ -37,26 +37,27 @@ class AvroName
/**
* @var string valid names are matched by self::NAME_REGEXP
*/
- private $name;
+ private string $name;
/**
- * @var string
+ * @var null|string
*/
- private $namespace;
+ private ?string $namespace;
/**
* @var string
*/
- private $fullname;
+ private string $fullname;
/**
* @var string Name qualified as necessary given its default namespace.
*/
- private $qualified_name;
+ private string $qualified_name;
/**
- * @param string $name
- * @param string $namespace
- * @param string $default_namespace
+ * @param mixed $name
+ * @param string|null $namespace
+ * @param string|null $default_namespace
+ * @throws AvroSchemaParseException
*/
- public function __construct($name, $namespace, $default_namespace)
+ public function __construct(mixed $name, ?string $namespace, ?string $default_namespace)
{
if (!is_string($name) || empty($name)) {
throw new AvroSchemaParseException('Name must be a non-empty string.');
@@ -82,11 +83,11 @@ public function __construct($name, $namespace, $default_namespace)
/**
* @param string $namespace
- * @returns boolean true if namespace is composed of valid names
+ * @return bool true if namespace is composed of valid names
* @throws AvroSchemaParseException if any of the namespace components
* are invalid.
*/
- private static function checkNamespaceNames($namespace)
+ private static function checkNamespaceNames(string $namespace): bool
{
foreach (explode(self::NAME_SEPARATOR, $namespace) as $n) {
if (empty($n) || (0 === preg_match(self::NAME_REGEXP, $n))) {
@@ -102,7 +103,7 @@ private static function checkNamespaceNames($namespace)
* @returns string
* @throws AvroSchemaParseException if any of the names are not valid.
*/
- private static function parseFullname($name, $namespace)
+ private static function parseFullname($name, $namespace): string
{
if (!is_string($namespace) || empty($namespace)) {
throw new AvroSchemaParseException('Namespace must be a non-empty string.');
@@ -112,9 +113,9 @@ private static function parseFullname($name, $namespace)
}
/**
- * @returns string[] array($name, $namespace)
+ * @return array{0: string, 1: null|string}
*/
- public static function extractNamespace($name, $namespace = null)
+ public static function extractNamespace(string $name, ?string $namespace = null): array
{
$parts = explode(self::NAME_SEPARATOR, $name);
if (count($parts) > 1) {
@@ -128,26 +129,26 @@ public static function extractNamespace($name, $namespace = null)
* @returns boolean true if the given name is well-formed
* (is a non-null, non-empty string) and false otherwise
*/
- public static function isWellFormedName($name)
+ public static function isWellFormedName($name): bool
{
return (is_string($name) && !empty($name) && preg_match(self::NAME_REGEXP, $name));
}
/**
- * @returns array array($name, $namespace)
+ * @return array{0: string, 1: string}
*/
- public function nameAndNamespace()
+ public function nameAndNamespace(): array
{
return [$this->name, $this->namespace];
}
/**
- * @returns string fullname
+ * @return string fullname
* @uses $this->fullname()
*/
- public function __toString()
+ public function __toString(): string
{
- return $this->fullname();
+ return (string) $this->fullname();
}
/**
@@ -165,4 +166,9 @@ public function qualifiedName()
{
return $this->qualified_name;
}
+
+ public function namespace(): ?string
+ {
+ return $this->namespace;
+ }
}
diff --git a/lang/php/lib/Schema/AvroNamedSchema.php b/lang/php/lib/Schema/AvroNamedSchema.php
index 7db254dbb7d..6449389cfdb 100644
--- a/lang/php/lib/Schema/AvroNamedSchema.php
+++ b/lang/php/lib/Schema/AvroNamedSchema.php
@@ -23,45 +23,23 @@
/**
* Parent class of named Avro schema
* @package Avro
- * @todo Refactor AvroNamedSchema to use an AvroName instance
- * to store name information.
*/
-class AvroNamedSchema extends AvroSchema
+class AvroNamedSchema extends AvroSchema implements AvroAliasedSchema
{
/**
- * @var AvroName $name
- */
- private $name;
-
- /**
- * @var string documentation string
- */
- private $doc;
- /**
- * @var array
- */
- private $aliases;
-
- /**
- * @param string $type
- * @param AvroName $name
- * @param string $doc documentation string
- * @param AvroNamedSchemata &$schemata
- * @param array $aliases
* @throws AvroSchemaParseException
*/
- public function __construct($type, $name, $doc = null, &$schemata = null, $aliases = null)
- {
+ public function __construct(
+ string $type,
+ private readonly AvroName $name,
+ private readonly ?string $doc = null,
+ ?AvroNamedSchemata &$schemata = null,
+ private ?array $aliases = null
+ ) {
parent::__construct($type);
- $this->name = $name;
- if ($doc && !is_string($doc)) {
- throw new AvroSchemaParseException('Schema doc attribute must be a string');
- }
- $this->doc = $doc;
- if ($aliases) {
- self::hasValidAliases($aliases);
- $this->aliases = $aliases;
+ if ($this->aliases) {
+ self::hasValidAliases($this->aliases);
}
if (!is_null($schemata)) {
@@ -69,15 +47,12 @@ public function __construct($type, $name, $doc = null, &$schemata = null, $alias
}
}
- public function getAliases()
+ public function getAliases(): ?array
{
return $this->aliases;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
[$name, $namespace] = AvroName::extractNamespace($this->qualifiedName());
@@ -94,16 +69,18 @@ public function toAvro()
return $avro;
}
- public function qualifiedName()
+ public function qualifiedName(): string
{
return $this->name->qualifiedName();
}
- /**
- * @returns string
- */
- public function fullname()
+ public function fullname(): string
{
return $this->name->fullname();
}
+
+ public function namespace(): ?string
+ {
+ return $this->name->namespace();
+ }
}
diff --git a/lang/php/lib/Schema/AvroNamedSchemata.php b/lang/php/lib/Schema/AvroNamedSchemata.php
index 1e7a88b2e18..82428dd4fa5 100644
--- a/lang/php/lib/Schema/AvroNamedSchemata.php
+++ b/lang/php/lib/Schema/AvroNamedSchemata.php
@@ -28,17 +28,13 @@
*/
class AvroNamedSchemata
{
- /**
- * @var AvroNamedSchema[]
- */
- private $schemata;
-
- /**
- * @param AvroNamedSchemata[]
- */
- public function __construct($schemata = array())
+ public function __construct(
+ /**
+ * @var AvroNamedSchema[]
+ */
+ private $schemata = []
+ )
{
- $this->schemata = $schemata;
}
public function listSchemas()
@@ -51,33 +47,30 @@ public function listSchemas()
/**
* @param AvroName $name
- * @returns AvroSchema|null
+ * @return AvroSchema|null
*/
- public function schemaByName($name)
+ public function schemaByName(AvroName $name): ?AvroSchema
{
return $this->schema($name->fullname());
}
/**
* @param string $fullname
- * @returns AvroSchema|null the schema which has the given name,
+ * @return AvroSchema|null the schema which has the given name,
* or null if there is no schema with the given name.
*/
- public function schema($fullname)
+ public function schema(string $fullname): ?AvroSchema
{
- if (isset($this->schemata[$fullname])) {
- return $this->schemata[$fullname];
- }
- return null;
+ return $this->schemata[$fullname] ?? null;
}
/**
* Creates a new AvroNamedSchemata instance of this schemata instance
* with the given $schema appended.
- * @param AvroNamedSchema schema to add to this existing schemata
- * @returns AvroNamedSchemata
+ * @param AvroNamedSchema $schema schema to add to this existing schemata
+ * @throws AvroSchemaParseException
*/
- public function cloneWithNewSchema($schema)
+ public function cloneWithNewSchema(AvroNamedSchema $schema): AvroNamedSchemata
{
$name = $schema->fullname();
if (AvroSchema::isValidType($name)) {
@@ -92,11 +85,10 @@ public function cloneWithNewSchema($schema)
}
/**
- * @param string $fullname
- * @returns boolean true if there exists a schema with the given name
+ * @returns bool true if there exists a schema with the given name
* and false otherwise.
*/
- public function hasName($fullname)
+ public function hasName(string $fullname): bool
{
return array_key_exists($fullname, $this->schemata);
}
diff --git a/lang/php/lib/Schema/AvroPrimitiveSchema.php b/lang/php/lib/Schema/AvroPrimitiveSchema.php
index 1c331a30373..6a483659ee9 100644
--- a/lang/php/lib/Schema/AvroPrimitiveSchema.php
+++ b/lang/php/lib/Schema/AvroPrimitiveSchema.php
@@ -31,7 +31,7 @@ class AvroPrimitiveSchema extends AvroSchema
* @throws AvroSchemaParseException if the given $type is not a
* primitive schema type name
*/
- public function __construct($type)
+ public function __construct(string $type)
{
if (!self::isPrimitiveType($type)) {
throw new AvroSchemaParseException(sprintf('%s is not a valid primitive type.', $type));
@@ -111,15 +111,13 @@ public static function localTimestampMicros(): self
return $self;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
- // FIXME: Is this if really necessary? When *wouldn't* this be the case?
- if (1 == count($avro)) {
+ // This check has been added (I guess) to avoid printing something like this for primitive types:
+ // {"name": "something", "type": {"type": "string"}}
+ if (1 === count($avro)) {
return $this->type;
}
diff --git a/lang/php/lib/Schema/AvroRecordSchema.php b/lang/php/lib/Schema/AvroRecordSchema.php
index 959ce5904ee..570f78f5a43 100644
--- a/lang/php/lib/Schema/AvroRecordSchema.php
+++ b/lang/php/lib/Schema/AvroRecordSchema.php
@@ -26,32 +26,23 @@
class AvroRecordSchema extends AvroNamedSchema
{
/**
- * @var AvroNamedSchema[] array of AvroNamedSchema field definitions of
+ * @var array array of AvroNamedSchema field definitions of
* this AvroRecordSchema
*/
- private $fields;
+ private array $fields;
/**
- * @var array map of field names to field objects.
+ * @var null|array map of field names to field objects.
* @internal Not called directly. Memoization of AvroRecordSchema->fieldsHash()
*/
- private $fieldsHash;
+ private ?array $fieldsHash = null;
- /**
- * @param AvroName $name
- * @param string $namespace
- * @param string $doc
- * @param array $fields
- * @param AvroNamedSchemata &$schemata
- * @param string $schema_type schema type name
- * @throws AvroSchemaParseException
- */
public function __construct(
- $name,
- $doc,
- $fields,
- &$schemata = null,
- $schema_type = AvroSchema::RECORD_SCHEMA,
- $aliases = null
+ AvroName $name,
+ ?string $doc,
+ ?array $fields,
+ ?AvroNamedSchemata &$schemata = null,
+ string $schema_type = AvroSchema::RECORD_SCHEMA,
+ ?array $aliases = null
) {
if (is_null($fields)) {
throw new AvroSchemaParseException(
@@ -59,7 +50,7 @@ public function __construct(
);
}
- if (AvroSchema::REQUEST_SCHEMA == $schema_type) {
+ if (AvroSchema::REQUEST_SCHEMA === $schema_type) {
parent::__construct($schema_type, $name);
} else {
parent::__construct($schema_type, $name, $doc, $schemata, $aliases);
@@ -70,22 +61,22 @@ public function __construct(
}
/**
- * @param mixed $field_data
- * @param string $default_namespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata
- * @returns AvroField[]
+ * @param null|string $default_namespace namespace of enclosing schema
* @throws AvroSchemaParseException
*/
- public static function parseFields($field_data, $default_namespace, &$schemata)
- {
- $fields = array();
- $field_names = array();
+ public static function parseFields(
+ array $field_data,
+ ?string $default_namespace,
+ ?AvroNamedSchemata $schemata = null
+ ): array {
+ $fields = [];
+ $field_names = [];
$alias_names = [];
- foreach ($field_data as $index => $field) {
+ foreach ($field_data as $field) {
$name = $field[AvroField::FIELD_NAME_ATTR] ?? null;
$type = $field[AvroSchema::TYPE_ATTR] ?? null;
$order = $field[AvroField::ORDER_ATTR] ?? null;
- $aliases = $field[AvroField::ALIASES_ATTR] ?? null;
+ $aliases = $field[AvroSchema::ALIASES_ATTR] ?? null;
$default = null;
$has_default = false;
@@ -109,22 +100,20 @@ public static function parseFields($field_data, $default_namespace, &$schemata)
)
) {
$is_schema_from_schemata = true;
+ } else if (is_string($type) && self::isPrimitiveType($type)) {
+ $field_schema = self::subparse($field, $default_namespace, $schemata);
} else {
- if (self::isPrimitiveType($type)) {
- $field_schema = self::subparse($field, $default_namespace, $schemata);
- } else {
- $field_schema = self::subparse($type, $default_namespace, $schemata);
- }
+ $field_schema = self::subparse($type, $default_namespace, $schemata);
}
$new_field = new AvroField(
- $name,
- $field_schema,
- $is_schema_from_schemata,
- $has_default,
- $default,
- $order,
- $aliases
+ name: $name,
+ schema: $field_schema,
+ isTypeFromSchemata: $is_schema_from_schemata,
+ hasDefault: $has_default,
+ default: $default,
+ order: $order,
+ aliases: $aliases
);
$field_names[] = $name;
if ($new_field->hasAliases() && array_intersect($alias_names, $new_field->getAliases())) {
@@ -138,14 +127,11 @@ public static function parseFields($field_data, $default_namespace, &$schemata)
return $fields;
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = parent::toAvro();
- $fields_avro = array();
+ $fields_avro = [];
foreach ($this->fields as $field) {
$fields_avro[] = $field->toAvro();
}
@@ -162,19 +148,19 @@ public function toAvro()
/**
* @returns array the schema definitions of the fields of this AvroRecordSchema
*/
- public function fields()
+ public function fields(): array
{
return $this->fields;
}
/**
- * @returns array a hash table of the fields of this AvroRecordSchema fields
+ * @return array a hash table of the fields of this AvroRecordSchema fields
* keyed by each field's name
*/
- public function fieldsHash()
+ public function fieldsHash(): array
{
if (is_null($this->fieldsHash)) {
- $hash = array();
+ $hash = [];
foreach ($this->fields as $field) {
$hash[$field->name()] = $field;
}
@@ -183,7 +169,7 @@ public function fieldsHash()
return $this->fieldsHash;
}
- public function fieldsByAlias()
+ public function fieldsByAlias(): array
{
$hash = [];
foreach ($this->fields as $field) {
diff --git a/lang/php/lib/Schema/AvroSchema.php b/lang/php/lib/Schema/AvroSchema.php
index 5a33ce1c9ec..4e80601c0ce 100644
--- a/lang/php/lib/Schema/AvroSchema.php
+++ b/lang/php/lib/Schema/AvroSchema.php
@@ -20,6 +20,7 @@
namespace Apache\Avro\Schema;
+use Apache\Avro\AvroException;
use Apache\Avro\AvroUtil;
use Apache\Avro\Datum\Type\AvroDuration;
@@ -52,7 +53,7 @@
/**
* @package Avro
*/
-class AvroSchema
+class AvroSchema implements \Stringable
{
/**
* @var int lower bound of integer values: -(1 << 31)
@@ -70,7 +71,7 @@ class AvroSchema
public const INT_RANGE = 4294967296;
/**
- * @var int lower bound of long values: -(1 << 63)
+ * @var float lower bound of long values: -(1 << 63)
*/
public const LONG_MIN_VALUE = -9223372036854775808;
@@ -268,7 +269,7 @@ class AvroSchema
/**
* @var array list of primitive schema type names
*/
- private static $primitiveTypes = array(
+ private static $primitiveTypes = [
self::NULL_TYPE,
self::BOOLEAN_TYPE,
self::STRING_TYPE,
@@ -277,21 +278,21 @@ class AvroSchema
self::LONG_TYPE,
self::FLOAT_TYPE,
self::DOUBLE_TYPE
- );
+ ];
/**
* @var array list of named schema type names
*/
- private static $namedTypes = array(
+ private static $namedTypes = [
self::FIXED_SCHEMA,
self::ENUM_SCHEMA,
self::RECORD_SCHEMA,
self::ERROR_SCHEMA
- );
+ ];
/**
* @var array list of names of reserved attributes
*/
- private static $reservedAttrs = array(
+ private static $reservedAttrs = [
self::TYPE_ATTR,
self::NAME_ATTR,
self::NAMESPACE_ATTR,
@@ -301,45 +302,45 @@ class AvroSchema
self::SYMBOLS_ATTR,
self::VALUES_ATTR,
self::LOGICAL_TYPE_ATTR,
- );
- /**
- * @var string|AvroNamedSchema
- */
- public $type;
+ ];
- /** @var null|AvroLogicalType */
- protected $logicalType = null;
+ protected ?AvroLogicalType $logicalType = null;
/**
- * @param string $type a schema type name
+ * @param string|AvroSchema $type a schema type name
* @internal Should only be called from within the constructor of
* a class which extends AvroSchema
*/
- public function __construct($type)
- {
- $this->type = $type;
+ public function __construct(
+ public readonly string|AvroSchema $type
+ ) {
}
/**
- * @param string $json JSON-encoded schema
* @uses self::realParse()
- * @returns AvroSchema
*/
- public static function parse($json)
+ public static function parse(string $json): AvroSchema
{
$schemata = new AvroNamedSchemata();
- return self::realParse(json_decode($json, true), null, $schemata);
+ return self::realParse(
+ avro: json_decode($json, true, JSON_THROW_ON_ERROR),
+ schemata: $schemata
+ );
}
/**
- * @param mixed $avro JSON-decoded schema
- * @param string $default_namespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata reference to named schemas
- * @returns AvroSchema
+ * @param null|array|string $avro JSON-decoded schema
+ * @param string|null $default_namespace namespace of enclosing schema
+ * @param AvroNamedSchemata|null $schemata reference to named schemas
+ * @return AvroSchema
* @throws AvroSchemaParseException
+ * @throws AvroException
*/
- public static function realParse($avro, $default_namespace = null, &$schemata = null)
- {
+ public static function realParse(
+ null|array|string $avro,
+ ?string $default_namespace = null,
+ ?AvroNamedSchemata &$schemata = null
+ ): AvroSchema {
if (is_null($schemata)) {
$schemata = new AvroNamedSchemata();
}
@@ -379,81 +380,80 @@ public static function realParse($avro, $default_namespace = null, &$schemata =
$new_name = new AvroName($name, $namespace, $default_namespace);
$doc = $avro[self::DOC_ATTR] ?? null;
$aliases = $avro[self::ALIASES_ATTR] ?? null;
+ AvroNamedSchema::hasValidAliases($aliases);
switch ($type) {
case self::FIXED_SCHEMA:
- $size = $avro[self::SIZE_ATTR] ?? null;
+ $size = $avro[self::SIZE_ATTR] ?? throw new AvroSchemaParseException(
+ "Size is required for fixed schema"
+ );
+ $size = (int) $size;
+
if (array_key_exists(self::LOGICAL_TYPE_ATTR, $avro)) {
switch ($avro[self::LOGICAL_TYPE_ATTR]) {
case self::DURATION_LOGICAL_TYPE:
return AvroFixedSchema::duration(
- $new_name,
- $doc,
- $schemata,
- $aliases
+ name: $new_name,
+ schemata: $schemata,
+ aliases: $aliases
);
case self::DECIMAL_LOGICAL_TYPE:
[$precision, $scale] = self::extractPrecisionAndScaleForDecimal($avro);
return AvroFixedSchema::decimal(
- $new_name,
- $doc,
- $size,
- $precision,
- $scale,
- $schemata,
- $aliases
+ name: $new_name,
+ size: $size,
+ precision: $precision,
+ scale: $scale,
+ schemata: $schemata,
+ aliases: $aliases
);
}
}
return new AvroFixedSchema(
- $new_name,
- $doc,
- $size,
- $schemata,
- $aliases
+ name: $new_name,
+ size: $size,
+ schemata: $schemata,
+ aliases: $aliases
);
case self::ENUM_SCHEMA:
$symbols = $avro[self::SYMBOLS_ATTR] ?? null;
return new AvroEnumSchema(
- $new_name,
- $doc,
- $symbols,
- $schemata,
- $aliases
+ name: $new_name,
+ doc: $doc,
+ symbols: $symbols,
+ schemata: $schemata,
+ aliases: $aliases
);
case self::RECORD_SCHEMA:
case self::ERROR_SCHEMA:
$fields = $avro[self::FIELDS_ATTR] ?? null;
return new AvroRecordSchema(
- $new_name,
- $doc,
- $fields,
- $schemata,
- $type,
- $aliases
+ name: $new_name,
+ doc: $doc,
+ fields: $fields,
+ schemata: $schemata,
+ schema_type: $type,
+ aliases: $aliases
);
default:
throw new AvroSchemaParseException(sprintf('Unknown named type: %s', $type));
}
} elseif (self::isValidType($type)) {
- switch ($type) {
- case self::ARRAY_SCHEMA:
- return new AvroArraySchema(
- $avro[self::ITEMS_ATTR],
- $default_namespace,
- $schemata
- );
- case self::MAP_SCHEMA:
- return new AvroMapSchema(
- $avro[self::VALUES_ATTR],
- $default_namespace,
- $schemata
- );
- default:
- throw new AvroSchemaParseException(
- sprintf('Unknown valid type: %s', $type)
- );
- }
+ return match ($type) {
+ self::ARRAY_SCHEMA => new AvroArraySchema(
+ items: $avro[self::ITEMS_ATTR],
+ defaultNamespace: $default_namespace,
+ schemata: $schemata
+ ),
+ self::MAP_SCHEMA => new AvroMapSchema(
+ values: $avro[self::VALUES_ATTR],
+ defaultNamespace: $default_namespace,
+ schemata: $schemata
+ ),
+ default => throw new AvroSchemaParseException(
+ sprintf('Unknown valid type: %s', $type)
+ ),
+ };
} elseif (
!array_key_exists(self::TYPE_ATTR, $avro)
&& AvroUtil::isList($avro)
@@ -486,39 +486,39 @@ public static function isValidType($type)
{
return (self::isPrimitiveType($type)
|| self::isNamedType($type)
- || in_array($type, array(
+ || in_array($type, [
self::ARRAY_SCHEMA,
self::MAP_SCHEMA,
self::UNION_SCHEMA,
self::REQUEST_SCHEMA,
self::ERROR_UNION_SCHEMA
- )));
+ ]));
}
/**
- * @param string $type a schema type name
+ * @param null|string $type a schema type name
* @returns boolean true if the given type name is a primitive schema type
* name and false otherwise.
*/
- public static function isPrimitiveType($type)
+ public static function isPrimitiveType(?string $type): bool
{
- return in_array($type, self::$primitiveTypes);
+ return in_array($type, self::$primitiveTypes, true);
}
/**
- * @param string $type a schema type name
- * @returns boolean true if the given type name is a named schema type name
+ * @param null|string $type a schema type name
+ * @returns bool true if the given type name is a named schema type name
* and false otherwise.
*/
- public static function isNamedType($type)
+ public static function isNamedType(?string $type): bool
{
- return in_array($type, self::$namedTypes);
+ return in_array($type, self::$namedTypes, true);
}
- public static function hasValidAliases($aliases)
+ public static function hasValidAliases($aliases): void
{
if ($aliases === null) {
- return false;
+ return;
}
if (!is_array($aliases)) {
throw new AvroSchemaParseException(
@@ -561,7 +561,7 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
case self::DOUBLE_TYPE:
return (is_float($datum) || is_int($datum));
case self::ARRAY_SCHEMA:
- if (is_array($datum)) {
+ if (is_array($datum) && $expected_schema instanceof AvroArraySchema) {
foreach ($datum as $d) {
if (!self::isValidDatum($expected_schema->items(), $d)) {
return false;
@@ -571,7 +571,7 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
}
return false;
case self::MAP_SCHEMA:
- if (is_array($datum)) {
+ if (is_array($datum) && $expected_schema instanceof AvroMapSchema) {
foreach ($datum as $k => $v) {
if (
!is_string($k)
@@ -584,6 +584,10 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
}
return false;
case self::UNION_SCHEMA:
+ if (!$expected_schema instanceof AvroUnionSchema) {
+ return false;
+ }
+
foreach ($expected_schema->schemas() as $schema) {
if (self::isValidDatum($schema, $datum)) {
return true;
@@ -591,8 +595,15 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
}
return false;
case self::ENUM_SCHEMA:
- return in_array($datum, $expected_schema->symbols());
+ if (!$expected_schema instanceof AvroEnumSchema) {
+ return false;
+ }
+ return in_array($datum, $expected_schema->symbols(), true);
case self::FIXED_SCHEMA:
+ if (!$expected_schema instanceof AvroFixedSchema) {
+ return false;
+ }
+
if (
$expected_schema->logicalType() instanceof AvroLogicalType
) {
@@ -618,6 +629,10 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
case self::RECORD_SCHEMA:
case self::ERROR_SCHEMA:
case self::REQUEST_SCHEMA:
+ if (!($expected_schema instanceof AvroRecordSchema)) {
+ return false;
+ }
+
if (is_array($datum)) {
foreach ($expected_schema->fields() as $field) {
if (!self::isValidDatum($field->type(), $datum[$field->name()] ?? null)) {
@@ -634,19 +649,17 @@ public static function isValidDatum(AvroSchema $expected_schema, $datum): bool
/**
* @param mixed $avro
- * @param string $default_namespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata
* @returns AvroSchema
* @throws AvroSchemaParseException
* @uses AvroSchema::realParse()
*/
- protected static function subparse($avro, $default_namespace, &$schemata = null)
+ protected static function subparse($avro, ?string $default_namespace, ?AvroNamedSchemata &$schemata = null): AvroSchema
{
try {
return self::realParse($avro, $default_namespace, $schemata);
} catch (AvroSchemaParseException $e) {
throw $e;
- } catch (\Exception $e) {
+ } catch (\Throwable) {
throw new AvroSchemaParseException(
sprintf(
'Sub-schema is not a valid Avro schema. Bad schema: %s',
@@ -672,12 +685,12 @@ public function logicalType(): ?AvroLogicalType
/**
* @returns string the JSON-encoded representation of this Avro schema.
*/
- public function __toString()
+ public function __toString(): string
{
- return (string) json_encode($this->toAvro());
+ return json_encode($this->toAvro(), JSON_THROW_ON_ERROR);
}
- public function toAvro()
+ public function toAvro(): string|array
{
$avro = [self::TYPE_ATTR => $this->type];
diff --git a/lang/php/lib/Schema/AvroUnionSchema.php b/lang/php/lib/Schema/AvroUnionSchema.php
index 796372a9d19..636cee3a8d1 100644
--- a/lang/php/lib/Schema/AvroUnionSchema.php
+++ b/lang/php/lib/Schema/AvroUnionSchema.php
@@ -31,23 +31,24 @@ class AvroUnionSchema extends AvroSchema
* @var int[] list of indices of named schemas which
* are defined in $schemata
*/
- public $schemaFromSchemataIndices;
+ public array $schemaFromSchemataIndices;
/**
* @var AvroSchema[] list of schemas of this union
*/
- private $schemas;
+ private array $schemas;
/**
* @param AvroSchema[] $schemas list of schemas in the union
- * @param string $defaultNamespace namespace of enclosing schema
- * @param AvroNamedSchemata &$schemata
+ * @param null|string $defaultNamespace namespace of enclosing schema
+ * @param null|AvroNamedSchemata &$schemata
+ * @throws AvroSchemaParseException
*/
- public function __construct($schemas, $defaultNamespace, &$schemata = null)
+ public function __construct(array $schemas, ?string $defaultNamespace, ?AvroNamedSchemata &$schemata = null)
{
parent::__construct(AvroSchema::UNION_SCHEMA);
- $this->schemaFromSchemataIndices = array();
- $schema_types = array();
+ $this->schemaFromSchemataIndices = [];
+ $schema_types = [];
foreach ($schemas as $index => $schema) {
$is_schema_from_schemata = false;
$new_schema = null;
@@ -86,17 +87,17 @@ public function __construct($schemas, $defaultNamespace, &$schemata = null)
/**
* @returns AvroSchema[]
*/
- public function schemas()
+ public function schemas(): array
{
return $this->schemas;
}
/**
- * @returns AvroSchema the particular schema from the union for
+ * @return AvroSchema the particular schema from the union for
* the given (zero-based) index.
* @throws AvroSchemaParseException if the index is invalid for this schema.
*/
- public function schemaByIndex($index)
+ public function schemaByIndex($index): AvroSchema
{
if (count($this->schemas) > $index) {
return $this->schemas[$index];
@@ -105,15 +106,12 @@ public function schemaByIndex($index)
throw new AvroSchemaParseException('Invalid union schema index');
}
- /**
- * @returns mixed
- */
- public function toAvro()
+ public function toAvro(): string|array
{
- $avro = array();
+ $avro = [];
foreach ($this->schemas as $index => $schema) {
- $avro[] = in_array($index, $this->schemaFromSchemataIndices)
+ $avro[] = in_array($index, $this->schemaFromSchemataIndices) && $schema instanceof AvroNamedSchema
? $schema->qualifiedName()
: $schema->toAvro();
}
diff --git a/lang/php/phpstan.neon b/lang/php/phpstan.neon
new file mode 100644
index 00000000000..1eae92a3e47
--- /dev/null
+++ b/lang/php/phpstan.neon
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+parameters:
+ level: 3
+ paths:
+ - lib
+ - test
+ bootstrapFiles:
+ - test/test_helper.php
diff --git a/lang/php/phpunit.xml b/lang/php/phpunit.xml
index 10584bc4aad..f4f5ead0114 100644
--- a/lang/php/phpunit.xml
+++ b/lang/php/phpunit.xml
@@ -15,30 +15,33 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
-
-
-
-
-
-
- test
- test/InterOpTest.php
-
-
-
-
-
- lib
-
-
+
+
+
+
+
+
+ test
+ test/InterOpTest.php
+
+
+
+
+ lib
+
+
diff --git a/lang/php/test/DataFileTest.php b/lang/php/test/DataFileTest.php
index d962866a828..dd8d77b3370 100644
--- a/lang/php/test/DataFileTest.php
+++ b/lang/php/test/DataFileTest.php
@@ -1,4 +1,5 @@
remove_data_files();
+ $this->dataFiles = [];
+ }
- public function test_write_read_nothing_round_trip()
+ protected function tearDown(): void
+ {
+ $this->remove_data_files();
+ }
+
+ public function test_write_read_nothing_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -49,28 +65,17 @@ public function test_write_read_nothing_round_trip()
}
}
- protected function add_data_file($data_file)
- {
- if (is_null($this->data_files)) {
- $this->data_files = array();
- }
- $data_file = "$data_file." . self::current_timestamp();
- $full = join(DIRECTORY_SEPARATOR, array(TEST_TEMP_DIR, $data_file));
- $this->data_files [] = $full;
- return $full;
- }
-
- public static function current_timestamp()
+ public static function current_timestamp(): string
{
- return date_format(new DateTime, 'Y-m-d H:i:s');
+ return (new \DateTime())->format('Y-m-d H:i:s');
}
- public function test_write_read_null_round_trip()
+ public function test_write_read_null_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -89,12 +94,12 @@ public function test_write_read_null_round_trip()
}
}
- public function test_write_read_string_round_trip()
+ public function test_write_read_string_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -113,12 +118,12 @@ public function test_write_read_string_round_trip()
}
}
- public function test_write_read_round_trip()
+ public function test_write_read_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -138,12 +143,12 @@ public function test_write_read_round_trip()
}
}
- public function test_write_read_true_round_trip()
+ public function test_write_read_true_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -162,12 +167,12 @@ public function test_write_read_true_round_trip()
}
}
- public function test_write_read_false_round_trip()
+ public function test_write_read_false_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
@@ -186,18 +191,18 @@ public function test_write_read_false_round_trip()
}
}
- public function test_write_read_int_array_round_trip()
+ public function test_write_read_int_array_round_trip(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
$data_file = $this->add_data_file(sprintf('data-wr-int-ary-%s.avr', $codec));
$writers_schema = '"int"';
- $data = array(10, 20, 30, 40, 50, 60, 70, 567, 89012345);
+ $data = [10, 20, 30, 40, 50, 60, 70, 567, 89012345];
$dw = AvroDataIO::openFile($data_file, 'w', $writers_schema, $codec);
foreach ($data as $datum) {
$dw->append($datum);
@@ -207,48 +212,55 @@ public function test_write_read_int_array_round_trip()
$dr = AvroDataIO::openFile($data_file);
$read_data = $dr->data();
$dr->close();
- $this->assertEquals($data, $read_data,
- sprintf("in: %s\nout: %s",
- json_encode($data), json_encode($read_data)));
+ $this->assertEquals(
+ $data,
+ $read_data,
+ sprintf(
+ "in: %s\nout: %s",
+ json_encode($data),
+ json_encode($read_data)
+ )
+ );
}
}
- public function test_differing_schemas_with_primitives()
+ public function test_differing_schemas_with_primitives(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
$data_file = $this->add_data_file(sprintf('data-prim-%s.avr', $codec));
$writer_schema = << 'john', 'age' => 25, 'verified' => true),
- array('username' => 'ryan', 'age' => 23, 'verified' => false)
- );
+ { "type": "record",
+ "name": "User",
+ "fields" : [
+ {"name": "username", "type": "string"},
+ {"name": "age", "type": "int"},
+ {"name": "verified", "type": "boolean", "default": "false"}
+ ]
+ }
+ JSON;
+ $data = [
+ ['username' => 'john', 'age' => 25, 'verified' => true],
+ ['username' => 'ryan', 'age' => 23, 'verified' => false],
+ ];
$dw = AvroDataIO::openFile($data_file, 'w', $writer_schema, $codec);
foreach ($data as $datum) {
$dw->append($datum);
}
$dw->close();
$reader_schema = <<data() as $index => $record) {
$this->assertEquals($data[$index]['username'], $record['username']);
@@ -256,36 +268,75 @@ public function test_differing_schemas_with_primitives()
}
}
- public function test_differing_schemas_with_complex_objects()
+ public function test_differing_schemas_with_complex_objects(): void
{
foreach (AvroDataIO::validCodecs() as $codec) {
if (
- ($codec === AvroDataIO::SNAPPY_CODEC && !extension_loaded('snappy'))
- || ($codec === AvroDataIO::ZSTANDARD_CODEC && !extension_loaded('zstd'))
+ (AvroDataIO::SNAPPY_CODEC === $codec && !extension_loaded('snappy'))
+ || (AvroDataIO::ZSTANDARD_CODEC === $codec && !extension_loaded('zstd'))
) {
continue;
}
$data_file = $this->add_data_file(sprintf('data-complex-%s.avr', $codec));
$writers_schema = << [1, 2, 3],
"something_map" => ["a" => 1, "b" => 2],
"something_record" => ["inner" => 2],
- "something_error" => ["code" => 403]
+ "something_error" => ["code" => 403],
],
[
"username" => "ryan",
@@ -304,8 +355,8 @@ public function test_differing_schemas_with_complex_objects()
"something_array" => [1, 2, 3],
"something_map" => ["a" => 2, "b" => 6],
"something_record" => ["inner" => 1],
- "something_error" => ["code" => 401]
- ]
+ "something_error" => ["code" => 401],
+ ],
];
$dw = AvroDataIO::openFile($data_file, 'w', $writers_schema, $codec);
foreach ($data as $datum) {
@@ -313,15 +364,15 @@ public function test_differing_schemas_with_complex_objects()
}
$dw->close();
- foreach (array(
- 'fixed',
- 'enum',
- 'record',
- 'error',
- 'array',
- 'map',
- 'union'
- ) as $s) {
+ foreach ([
+ 'fixed',
+ 'enum',
+ 'record',
+ 'error',
+ 'array',
+ 'map',
+ 'union',
+ ] as $s) {
$readers_schema = json_decode($writers_schema, true);
$dr = AvroDataIO::openFile($data_file, 'r', json_encode($readers_schema));
foreach ($dr->data() as $idx => $obj) {
@@ -335,32 +386,28 @@ public function test_differing_schemas_with_complex_objects()
}
}
- protected function setUp(): void
+ protected function add_data_file(string $data_file): string
{
- if (!file_exists(TEST_TEMP_DIR)) {
- mkdir(TEST_TEMP_DIR);
- }
- $this->remove_data_files();
+ $data_file = "$data_file.".self::current_timestamp();
+ $full = implode(DIRECTORY_SEPARATOR, [TEST_TEMP_DIR, $data_file]);
+ $this->dataFiles[] = $full;
+
+ return $full;
}
- protected function remove_data_files()
+ protected function remove_data_files(): void
{
- if (self::REMOVE_DATA_FILES && $this->data_files) {
- foreach ($this->data_files as $data_file) {
+ if (self::REMOVE_DATA_FILES && $this->dataFiles) {
+ foreach ($this->dataFiles as $data_file) {
self::remove_data_file($data_file);
}
}
}
- protected static function remove_data_file($data_file)
+ protected static function remove_data_file($data_file): void
{
if (file_exists($data_file)) {
unlink($data_file);
}
}
-
- protected function tearDown(): void
- {
- $this->remove_data_files();
- }
}
diff --git a/lang/php/test/DatumIOTest.php b/lang/php/test/DatumIOTest.php
index a29cf06f064..717ee78a247 100644
--- a/lang/php/test/DatumIOTest.php
+++ b/lang/php/test/DatumIOTest.php
@@ -1,4 +1,5 @@
assertIsValidDatumForSchema($schema_json, $datum, $binary);
}
@@ -61,11 +55,11 @@ public static function data_provider(): array
['"int"', 2147483647, "\xFE\xFF\xFF\xFF\x0F"],
['"long"', (int) -9223372036854775808, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"],
- ['"long"', -(1<<62), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"],
- ['"long"', -(1<<61), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"],
+ ['"long"', -(1 << 62), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"],
+ ['"long"', -(1 << 61), "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"],
['"long"', -4294967295, "\xFD\xFF\xFF\xFF\x1F"],
- ['"long"', -1<<24, "\xFF\xFF\xFF\x0F"],
- ['"long"', -1<<16, "\xFF\xFF\x07"],
+ ['"long"', -1 << 24, "\xFF\xFF\xFF\x0F"],
+ ['"long"', -1 << 16, "\xFF\xFF\x07"],
['"long"', -255, "\xFD\x03"],
['"long"', -128, "\xFF\x01"],
['"long"', -127, "\xFD\x01"],
@@ -81,11 +75,11 @@ public static function data_provider(): array
['"long"', 127, "\xFE\x01"],
['"long"', 128, "\x80\x02"],
['"long"', 255, "\xFE\x03"],
- ['"long"', 1<<16, "\x80\x80\x08"],
- ['"long"', 1<<24, "\x80\x80\x80\x10"],
+ ['"long"', 1 << 16, "\x80\x80\x08"],
+ ['"long"', 1 << 24, "\x80\x80\x80\x10"],
['"long"', 4294967295, "\xFE\xFF\xFF\xFF\x1F"],
- ['"long"', 1<<61, "\x80\x80\x80\x80\x80\x80\x80\x80\x40"],
- ['"long"', 1<<62, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"],
+ ['"long"', 1 << 61, "\x80\x80\x80\x80\x80\x80\x80\x80\x40"],
+ ['"long"', 1 << 62, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x01"],
['"long"', 9223372036854775807, "\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x01"],
['"float"', (float) -10.0, "\000\000 \301"],
@@ -94,11 +88,11 @@ public static function data_provider(): array
['"float"', (float) 2.0, "\000\000\000@"],
['"float"', (float) 9.0, "\000\000\020A"],
- ['"double"', (double) -10.0, "\000\000\000\000\000\000$\300"],
- ['"double"', (double) -1.0, "\000\000\000\000\000\000\360\277"],
- ['"double"', (double) 0.0, "\000\000\000\000\000\000\000\000"],
- ['"double"', (double) 2.0, "\000\000\000\000\000\000\000@"],
- ['"double"', (double) 9.0, "\000\000\000\000\000\000\"@"],
+ ['"double"', (float) -10.0, "\000\000\000\000\000\000$\300"],
+ ['"double"', (float) -1.0, "\000\000\000\000\000\000\360\277"],
+ ['"double"', (float) 0.0, "\000\000\000\000\000\000\000\000"],
+ ['"double"', (float) 2.0, "\000\000\000\000\000\000\000@"],
+ ['"double"', (float) 9.0, "\000\000\000\000\000\000\"@"],
['"string"', 'foo', "\x06foo"],
['"bytes"', "\x01\x02\x03", "\x06\x01\x02\x03"],
@@ -106,28 +100,28 @@ public static function data_provider(): array
[
'{"type":"array","items":"int"}',
[1, 2, 3],
- "\x06\x02\x04\x06\x00"
+ "\x06\x02\x04\x06\x00",
],
[
'{"type":"map","values":"int"}',
['foo' => 1, 'bar' => 2, 'baz' => 3],
- "\x06\x06foo\x02\x06bar\x04\x06baz\x06\x00"
+ "\x06\x06foo\x02\x06bar\x04\x06baz\x06\x00",
],
['["null", "int"]', 1, "\x02\x02"],
[
'{"name":"fix","type":"fixed","size":3}',
"\xAA\xBB\xCC",
- "\xAA\xBB\xCC"
+ "\xAA\xBB\xCC",
],
[
'{"name":"enm","type":"enum","symbols":["A","B","C"]}',
'B',
- "\x02"
+ "\x02",
],
[
'{"name":"rec","type":"record","fields":[{"name":"a","type":"int"},{"name":"b","type":"boolean"}]}',
['a' => 1, 'b' => false],
- "\x02\x00"
+ "\x02\x00",
],
];
}
@@ -216,48 +210,46 @@ public static function validBytesDecimalLogicalType(): array
];
}
- /**
- * @dataProvider validBytesDecimalLogicalType
- */
- public function testValidBytesDecimalLogicalType(string $datum, int $precision, int $scale, string $expected): void
+ #[DataProvider('validBytesDecimalLogicalType')]
+ public function test_valid_bytes_decimal_logical_type(string $datum, int $precision, int $scale, string $expected): void
{
$bytesSchemaJson = <<assertIsValidDatumForSchema($bytesSchemaJson, $datum, $expected);
$fixedSchemaJson = <<assertIsValidDatumForSchema($fixedSchemaJson, $datum, $expected);
}
- public function testInvalidBytesLogicalTypeOutOfRange(): void
+ public function test_invalid_bytes_logical_type_out_of_range(): void
{
$schemaJson = <<assertIsValidDatumForSchema(
$bytesSchemaJson,
@@ -311,10 +301,8 @@ public static function durationLogicalTypeOutOfBounds(): array
];
}
- /**
- * @dataProvider durationLogicalTypeOutOfBounds
- */
- public function testDurationLogicalTypeOutOfBounds(int $months, int $days, int $milliseconds): void
+ #[DataProvider('durationLogicalTypeOutOfBounds')]
+ public function test_duration_logical_type_out_of_bounds(int $months, int $days, int $milliseconds): void
{
$this->expectException(AvroException::class);
new AvroDuration($months, $days, $milliseconds);
@@ -365,7 +353,7 @@ public static function default_provider(): array
[
'{"type":"array","items":"int"}',
'[5,4,3,2]',
- [5, 4, 3, 2]
+ [5, 4, 3, 2],
],
[
'{"type":"map","values":"int"}',
@@ -407,20 +395,20 @@ public static function default_provider(): array
];
}
- /**
- * @dataProvider default_provider
- */
+ #[DataProvider('default_provider')]
public function test_field_default_value(
- $field_schema_json,
- $default_json,
- $default_value
+ string $field_schema_json,
+ string $default_json,
+ mixed $default_value
): void {
$writers_schema_json = '{"name":"foo","type":"record","fields":[]}';
$writers_schema = AvroSchema::parse($writers_schema_json);
$readers_schema_json = sprintf(
'{"name":"foo","type":"record","fields":[{"name":"f","type":%s,"default":%s}]}',
- $field_schema_json, $default_json);
+ $field_schema_json,
+ $default_json
+ );
$readers_schema = AvroSchema::parse($readers_schema_json);
$reader = new AvroIODatumReader($writers_schema, $readers_schema);
@@ -428,16 +416,16 @@ public function test_field_default_value(
if (array_key_exists('f', $record)) {
$this->assertEquals($default_value, $record['f']);
} else {
- $this->assertTrue(false, sprintf('expected field record[f]: %s',
- print_r($record, true)));
+ $this->assertTrue(false, sprintf(
+ 'expected field record[f]: %s',
+ print_r($record, true)
+ ));
}
}
/**
- * @param string $schemaJson
* @param string $datum
* @param string $expected
- * @return void
* @throws \Apache\Avro\IO\AvroIOException
*/
private function assertIsValidDatumForSchema(string $schemaJson, $datum, $expected): void
@@ -449,10 +437,15 @@ private function assertIsValidDatumForSchema(string $schemaJson, $datum, $expect
$writer->write($datum, $encoder);
$output = (string) $written;
- $this->assertEquals($expected, $output,
- sprintf("expected: %s\n actual: %s",
+ $this->assertEquals(
+ $expected,
+ $output,
+ sprintf(
+ "expected: %s\n actual: %s",
AvroDebug::asciiString($expected, 'hex'),
- AvroDebug::asciiString($output, 'hex')));
+ AvroDebug::asciiString($output, 'hex')
+ )
+ );
$read = new AvroStringIO((string) $expected);
$decoder = new AvroIOBinaryDecoder($read);
diff --git a/lang/php/test/FloatIntEncodingTest.php b/lang/php/test/FloatIntEncodingTest.php
index 07492cfadae..24afc849c62 100644
--- a/lang/php/test/FloatIntEncodingTest.php
+++ b/lang/php/test/FloatIntEncodingTest.php
@@ -1,4 +1,5 @@
assertIsFloat(self::$FLOAT_NAN, 'float NaN is a float');
- $this->assertTrue(is_nan(self::$FLOAT_NAN), 'float NaN is NaN');
- $this->assertFalse(is_infinite(self::$FLOAT_NAN), 'float NaN is not infinite');
-
- $this->assertIsFloat(self::$FLOAT_POS_INF, 'float pos infinity is a float');
- $this->assertTrue(is_infinite(self::$FLOAT_POS_INF), 'float pos infinity is infinite');
- $this->assertTrue(0 < self::$FLOAT_POS_INF, 'float pos infinity is greater than 0');
- $this->assertFalse(is_nan(self::$FLOAT_POS_INF), 'float pos infinity is not NaN');
-
- $this->assertIsFloat(self::$FLOAT_NEG_INF, 'float neg infinity is a float');
- $this->assertTrue(is_infinite(self::$FLOAT_NEG_INF), 'float neg infinity is infinite');
- $this->assertTrue(0 > self::$FLOAT_NEG_INF, 'float neg infinity is less than 0');
- $this->assertFalse(is_nan(self::$FLOAT_NEG_INF), 'float neg infinity is not NaN');
-
- $this->assertIsFloat(self::$DOUBLE_NAN, 'double NaN is a double');
- $this->assertTrue(is_nan(self::$DOUBLE_NAN), 'double NaN is NaN');
- $this->assertFalse(is_infinite(self::$DOUBLE_NAN), 'double NaN is not infinite');
-
- $this->assertIsFloat(self::$DOUBLE_POS_INF, 'double pos infinity is a double');
- $this->assertTrue(is_infinite(self::$DOUBLE_POS_INF), 'double pos infinity is infinite');
- $this->assertTrue(0 < self::$DOUBLE_POS_INF, 'double pos infinity is greater than 0');
- $this->assertFalse(is_nan(self::$DOUBLE_POS_INF), 'double pos infinity is not NaN');
-
- $this->assertIsFloat(self::$DOUBLE_NEG_INF, 'double neg infinity is a double');
- $this->assertTrue(is_infinite(self::$DOUBLE_NEG_INF), 'double neg infinity is infinite');
- $this->assertTrue(0 > self::$DOUBLE_NEG_INF, 'double neg infinity is less than 0');
- $this->assertFalse(is_nan(self::$DOUBLE_NEG_INF), 'double neg infinity is not NaN');
-
- }
-
- function special_vals_provider()
- {
- self::make_special_vals();
- return array(array(self::DOUBLE_TYPE, self::$DOUBLE_POS_INF, self::$LONG_BITS_POS_INF),
- array(self::DOUBLE_TYPE, self::$DOUBLE_NEG_INF, self::$LONG_BITS_NEG_INF),
- array(self::FLOAT_TYPE, self::$FLOAT_POS_INF, self::$INT_BITS_POS_INF),
- array(self::FLOAT_TYPE, self::$FLOAT_NEG_INF, self::$INT_BITS_NEG_INF));
- }
-
- /**
- * @dataProvider special_vals_provider
- */
- function test_encoding_special_values($type, $val, $bits)
- {
- $this->assert_encode_values($type, $val, $bits);
- }
-
- function nan_vals_provider()
- {
- self::make_special_vals();
- return array(array(self::DOUBLE_TYPE, self::$DOUBLE_NAN, self::$LONG_BITS_NAN),
- array(self::FLOAT_TYPE, self::$FLOAT_NAN, self::$INT_BITS_NAN));
- }
-
- /**
- * @dataProvider nan_vals_provider
- */
- function test_encoding_nan_values($type, $val, $bits)
- {
- $this->assert_encode_nan_values($type, $val, $bits);
- }
-
- function normal_vals_provider()
- {
- $ruby_to_generate_vals =<<<_RUBY
- def d2lb(d); [d].pack('E') end
- dary = (-10..10).to_a + [-1234.2132, -211e23]
- dary.each {|x| b = d2lb(x); puts %/array(self::DOUBLE_TYPE, (double) #{x}, #{b.inspect}, '#{b.unpack('h*')[0]}'),/}
- def f2ib(f); [f].pack('e') end
- fary = (-10..10).to_a + [-1234.5, -211.3e6]
- fary.each {|x| b = f2ib(x); puts %/array(self::FLOAT_TYPE, (float) #{x}, #{b.inspect}, '#{b.unpack('h*')[0]}'),/}
-_RUBY;
-
- return array(
- array(self::DOUBLE_TYPE, (double) -10, "\000\000\000\000\000\000$\300", '000000000000420c'),
- array(self::DOUBLE_TYPE, (double) -9, "\000\000\000\000\000\000\"\300", '000000000000220c'),
- array(self::DOUBLE_TYPE, (double) -8, "\000\000\000\000\000\000 \300", '000000000000020c'),
- array(self::DOUBLE_TYPE, (double) -7, "\000\000\000\000\000\000\034\300", '000000000000c10c'),
- array(self::DOUBLE_TYPE, (double) -6, "\000\000\000\000\000\000\030\300", '000000000000810c'),
- array(self::DOUBLE_TYPE, (double) -5, "\000\000\000\000\000\000\024\300", '000000000000410c'),
- array(self::DOUBLE_TYPE, (double) -4, "\000\000\000\000\000\000\020\300", '000000000000010c'),
- /**/ array(self::DOUBLE_TYPE, (double) -3, "\000\000\000\000\000\000\010\300", '000000000000800c'),
- array(self::DOUBLE_TYPE, (double) -2, "\000\000\000\000\000\000\000\300", '000000000000000c'),
- array(self::DOUBLE_TYPE, (double) -1, "\000\000\000\000\000\000\360\277", '0000000000000ffb'),
- array(self::DOUBLE_TYPE, (double) 0, "\000\000\000\000\000\000\000\000", '0000000000000000'),
- array(self::DOUBLE_TYPE, (double) 1, "\000\000\000\000\000\000\360?", '0000000000000ff3'),
- array(self::DOUBLE_TYPE, (double) 2, "\000\000\000\000\000\000\000@", '0000000000000004'),
- /**/ array(self::DOUBLE_TYPE, (double) 3, "\000\000\000\000\000\000\010@", '0000000000008004'),
- array(self::DOUBLE_TYPE, (double) 4, "\000\000\000\000\000\000\020@", '0000000000000104'),
- array(self::DOUBLE_TYPE, (double) 5, "\000\000\000\000\000\000\024@", '0000000000004104'),
- array(self::DOUBLE_TYPE, (double) 6, "\000\000\000\000\000\000\030@", '0000000000008104'),
- array(self::DOUBLE_TYPE, (double) 7, "\000\000\000\000\000\000\034@", '000000000000c104'),
- array(self::DOUBLE_TYPE, (double) 8, "\000\000\000\000\000\000 @", '0000000000000204'),
- array(self::DOUBLE_TYPE, (double) 9, "\000\000\000\000\000\000\"@", '0000000000002204'),
- array(self::DOUBLE_TYPE, (double) 10, "\000\000\000\000\000\000$@", '0000000000004204'),
- /**/ array(self::DOUBLE_TYPE, (double) -1234.2132, "\007\316\031Q\332H\223\300", '70ec9115ad84390c'),
- array(self::DOUBLE_TYPE, (double) -2.11e+25, "\311\260\276J\031t1\305", '9c0beba49147135c'),
-
- array(self::FLOAT_TYPE, (float) -10, "\000\000 \301", '0000021c'),
- array(self::FLOAT_TYPE, (float) -9, "\000\000\020\301", '0000011c'),
- array(self::FLOAT_TYPE, (float) -8, "\000\000\000\301", '0000001c'),
- array(self::FLOAT_TYPE, (float) -7, "\000\000\340\300", '00000e0c'),
- array(self::FLOAT_TYPE, (float) -6, "\000\000\300\300", '00000c0c'),
- array(self::FLOAT_TYPE, (float) -5, "\000\000\240\300", '00000a0c'),
- array(self::FLOAT_TYPE, (float) -4, "\000\000\200\300", '0000080c'),
- array(self::FLOAT_TYPE, (float) -3, "\000\000@\300", '0000040c'),
- array(self::FLOAT_TYPE, (float) -2, "\000\000\000\300", '0000000c'),
- array(self::FLOAT_TYPE, (float) -1, "\000\000\200\277", '000008fb'),
- array(self::FLOAT_TYPE, (float) 0, "\000\000\000\000", '00000000'),
- array(self::FLOAT_TYPE, (float) 1, "\000\000\200?", '000008f3'),
- array(self::FLOAT_TYPE, (float) 2, "\000\000\000@", '00000004'),
- array(self::FLOAT_TYPE, (float) 3, "\000\000@@", '00000404'),
- array(self::FLOAT_TYPE, (float) 4, "\000\000\200@", '00000804'),
- array(self::FLOAT_TYPE, (float) 5, "\000\000\240@", '00000a04'),
- array(self::FLOAT_TYPE, (float) 6, "\000\000\300@", '00000c04'),
- array(self::FLOAT_TYPE, (float) 7, "\000\000\340@", '00000e04'),
- array(self::FLOAT_TYPE, (float) 8, "\000\000\000A", '00000014'),
- array(self::FLOAT_TYPE, (float) 9, "\000\000\020A", '00000114'),
- array(self::FLOAT_TYPE, (float) 10, "\000\000 A", '00000214'),
- array(self::FLOAT_TYPE, (float) -1234.5, "\000P\232\304", '0005a94c'),
- array(self::FLOAT_TYPE, (float) -211300000.0, "\352\202I\315", 'ae2894dc'),
- );
- }
-
- function float_vals_provider()
- {
- $ary = array();
-
- foreach ($this->normal_vals_provider() as $values)
- if (self::FLOAT_TYPE == $values[0])
- $ary []= array($values[0], $values[1], $values[2]);
-
- return $ary;
- }
-
- function double_vals_provider()
- {
- $ary = array();
-
- foreach ($this->normal_vals_provider() as $values)
- if (self::DOUBLE_TYPE == $values[0])
- $ary []= array($values[0], $values[1], $values[2]);
-
- return $ary;
- }
-
-
- /**
- * @dataProvider float_vals_provider
- */
- function test_encoding_float_values($type, $val, $bits)
- {
- $this->assert_encode_values($type, $val, $bits);
- }
-
- /**
- * @dataProvider double_vals_provider
- */
- function test_encoding_double_values($type, $val, $bits)
- {
- $this->assert_encode_values($type, $val, $bits);
- }
-
- function assert_encode_values($type, $val, $bits)
- {
- if (self::FLOAT_TYPE == $type)
+ public const FLOAT_TYPE = 'float';
+ public const DOUBLE_TYPE = 'double';
+
+ public static float $FLOAT_NAN;
+ public static float $FLOAT_POS_INF;
+ public static float $FLOAT_NEG_INF;
+ public static float $DOUBLE_NAN;
+ public static float $DOUBLE_POS_INF;
+ public static float $DOUBLE_NEG_INF;
+
+ public static string $LONG_BITS_NAN;
+ public static string $LONG_BITS_POS_INF;
+ public static string $LONG_BITS_NEG_INF;
+ public static string $INT_BITS_NAN;
+ public static string $INT_BITS_POS_INF;
+ public static string $INT_BITS_NEG_INF;
+
+ public function setUp(): void
+ {
+ self::make_special_vals();
+ }
+
+ public static function make_special_vals()
+ {
+ self::$DOUBLE_NAN = (float) NAN;
+ self::$DOUBLE_POS_INF = (float) INF;
+ self::$DOUBLE_NEG_INF = (float) -INF;
+ self::$FLOAT_NAN = (float) NAN;
+ self::$FLOAT_POS_INF = (float) INF;
+ self::$FLOAT_NEG_INF = (float) -INF;
+
+ self::$LONG_BITS_NAN = strrev(pack('H*', '7ff8000000000000'));
+ self::$LONG_BITS_POS_INF = strrev(pack('H*', '7ff0000000000000'));
+ self::$LONG_BITS_NEG_INF = strrev(pack('H*', 'fff0000000000000'));
+ self::$INT_BITS_NAN = strrev(pack('H*', '7fc00000'));
+ self::$INT_BITS_POS_INF = strrev(pack('H*', '7f800000'));
+ self::$INT_BITS_NEG_INF = strrev(pack('H*', 'ff800000'));
+ }
+
+ public function test_special_values(): void
+ {
+ $this->assertIsFloat(self::$FLOAT_NAN, 'float NaN is a float');
+ $this->assertTrue(is_nan(self::$FLOAT_NAN), 'float NaN is NaN');
+ $this->assertFalse(is_infinite(self::$FLOAT_NAN), 'float NaN is not infinite');
+
+ $this->assertIsFloat(self::$FLOAT_POS_INF, 'float pos infinity is a float');
+ $this->assertTrue(is_infinite(self::$FLOAT_POS_INF), 'float pos infinity is infinite');
+ $this->assertTrue(0 < self::$FLOAT_POS_INF, 'float pos infinity is greater than 0');
+ $this->assertFalse(is_nan(self::$FLOAT_POS_INF), 'float pos infinity is not NaN');
+
+ $this->assertIsFloat(self::$FLOAT_NEG_INF, 'float neg infinity is a float');
+ $this->assertTrue(is_infinite(self::$FLOAT_NEG_INF), 'float neg infinity is infinite');
+ $this->assertTrue(0 > self::$FLOAT_NEG_INF, 'float neg infinity is less than 0');
+ $this->assertFalse(is_nan(self::$FLOAT_NEG_INF), 'float neg infinity is not NaN');
+
+ $this->assertIsFloat(self::$DOUBLE_NAN, 'double NaN is a double');
+ $this->assertTrue(is_nan(self::$DOUBLE_NAN), 'double NaN is NaN');
+ $this->assertFalse(is_infinite(self::$DOUBLE_NAN), 'double NaN is not infinite');
+
+ $this->assertIsFloat(self::$DOUBLE_POS_INF, 'double pos infinity is a double');
+ $this->assertTrue(is_infinite(self::$DOUBLE_POS_INF), 'double pos infinity is infinite');
+ $this->assertTrue(0 < self::$DOUBLE_POS_INF, 'double pos infinity is greater than 0');
+ $this->assertFalse(is_nan(self::$DOUBLE_POS_INF), 'double pos infinity is not NaN');
+
+ $this->assertIsFloat(self::$DOUBLE_NEG_INF, 'double neg infinity is a double');
+ $this->assertTrue(is_infinite(self::$DOUBLE_NEG_INF), 'double neg infinity is infinite');
+ $this->assertTrue(0 > self::$DOUBLE_NEG_INF, 'double neg infinity is less than 0');
+ $this->assertFalse(is_nan(self::$DOUBLE_NEG_INF), 'double neg infinity is not NaN');
+
+ }
+
+ public static function special_vals_provider(): array
+ {
+ self::make_special_vals();
+
+ return [
+ [self::DOUBLE_TYPE, self::$DOUBLE_POS_INF, self::$LONG_BITS_POS_INF],
+ [self::DOUBLE_TYPE, self::$DOUBLE_NEG_INF, self::$LONG_BITS_NEG_INF],
+ [self::FLOAT_TYPE, self::$FLOAT_POS_INF, self::$INT_BITS_POS_INF],
+ [self::FLOAT_TYPE, self::$FLOAT_NEG_INF, self::$INT_BITS_NEG_INF],
+ ];
+ }
+
+ #[DataProvider('special_vals_provider')]
+ public function test_encoding_special_values(string $type, mixed $val, mixed $bits): void
+ {
+ $this->assert_encode_values($type, $val, $bits);
+ }
+
+ public static function nan_vals_provider(): array
+ {
+ self::make_special_vals();
+
+ return [
+ [self::DOUBLE_TYPE, self::$DOUBLE_NAN, self::$LONG_BITS_NAN],
+ [self::FLOAT_TYPE, self::$FLOAT_NAN, self::$INT_BITS_NAN],
+ ];
+ }
+
+ #[DataProvider('nan_vals_provider')]
+ public function test_encoding_nan_values(string $type, float $val, string $bits): void
{
- $decoder = array(AvroIOBinaryDecoder::class, 'intBitsToFloat');
- $encoder = array(AvroIOBinaryEncoder::class, 'floatToIntBits');
+ $this->assert_encode_nan_values($type, $val, $bits);
}
- else
+
+ public static function normal_vals_provider(): array
{
- $decoder = array(AvroIOBinaryDecoder::class, 'longBitsToDouble');
- $encoder = array(AvroIOBinaryEncoder::class, 'doubleToLongBits');
+ $ruby_to_generate_vals = <<<_RUBY
+ def d2lb(d); [d].pack('E') end
+ dary = (-10..10).to_a + [-1234.2132, -211e23]
+ dary.each {|x| b = d2lb(x); puts %/array(self::DOUBLE_TYPE, (double) #{x}, #{b.inspect}, '#{b.unpack('h*')[0]}'),/}
+ def f2ib(f); [f].pack('e') end
+ fary = (-10..10).to_a + [-1234.5, -211.3e6]
+ fary.each {|x| b = f2ib(x); puts %/array(self::FLOAT_TYPE, (float) #{x}, #{b.inspect}, '#{b.unpack('h*')[0]}'),/}
+ _RUBY;
+
+ return [
+ [self::DOUBLE_TYPE, (float) -10, "\000\000\000\000\000\000$\300", '000000000000420c'],
+ [self::DOUBLE_TYPE, (float) -9, "\000\000\000\000\000\000\"\300", '000000000000220c'],
+ [self::DOUBLE_TYPE, (float) -8, "\000\000\000\000\000\000 \300", '000000000000020c'],
+ [self::DOUBLE_TYPE, (float) -7, "\000\000\000\000\000\000\034\300", '000000000000c10c'],
+ [self::DOUBLE_TYPE, (float) -6, "\000\000\000\000\000\000\030\300", '000000000000810c'],
+ [self::DOUBLE_TYPE, (float) -5, "\000\000\000\000\000\000\024\300", '000000000000410c'],
+ [self::DOUBLE_TYPE, (float) -4, "\000\000\000\000\000\000\020\300", '000000000000010c'],
+ [self::DOUBLE_TYPE, (float) -3, "\000\000\000\000\000\000\010\300", '000000000000800c'],
+ [self::DOUBLE_TYPE, (float) -2, "\000\000\000\000\000\000\000\300", '000000000000000c'],
+ [self::DOUBLE_TYPE, (float) -1, "\000\000\000\000\000\000\360\277", '0000000000000ffb'],
+ [self::DOUBLE_TYPE, (float) 0, "\000\000\000\000\000\000\000\000", '0000000000000000'],
+ [self::DOUBLE_TYPE, (float) 1, "\000\000\000\000\000\000\360?", '0000000000000ff3'],
+ [self::DOUBLE_TYPE, (float) 2, "\000\000\000\000\000\000\000@", '0000000000000004'],
+ [self::DOUBLE_TYPE, (float) 3, "\000\000\000\000\000\000\010@", '0000000000008004'],
+ [self::DOUBLE_TYPE, (float) 4, "\000\000\000\000\000\000\020@", '0000000000000104'],
+ [self::DOUBLE_TYPE, (float) 5, "\000\000\000\000\000\000\024@", '0000000000004104'],
+ [self::DOUBLE_TYPE, (float) 6, "\000\000\000\000\000\000\030@", '0000000000008104'],
+ [self::DOUBLE_TYPE, (float) 7, "\000\000\000\000\000\000\034@", '000000000000c104'],
+ [self::DOUBLE_TYPE, (float) 8, "\000\000\000\000\000\000 @", '0000000000000204'],
+ [self::DOUBLE_TYPE, (float) 9, "\000\000\000\000\000\000\"@", '0000000000002204'],
+ [self::DOUBLE_TYPE, (float) 10, "\000\000\000\000\000\000$@", '0000000000004204'],
+ [self::DOUBLE_TYPE, (float) -1234.2132, "\007\316\031Q\332H\223\300", '70ec9115ad84390c'],
+ [self::DOUBLE_TYPE, (float) -2.11e+25, "\311\260\276J\031t1\305", '9c0beba49147135c'],
+
+ [self::FLOAT_TYPE, (float) -10, "\000\000 \301", '0000021c'],
+ [self::FLOAT_TYPE, (float) -9, "\000\000\020\301", '0000011c'],
+ [self::FLOAT_TYPE, (float) -8, "\000\000\000\301", '0000001c'],
+ [self::FLOAT_TYPE, (float) -7, "\000\000\340\300", '00000e0c'],
+ [self::FLOAT_TYPE, (float) -6, "\000\000\300\300", '00000c0c'],
+ [self::FLOAT_TYPE, (float) -5, "\000\000\240\300", '00000a0c'],
+ [self::FLOAT_TYPE, (float) -4, "\000\000\200\300", '0000080c'],
+ [self::FLOAT_TYPE, (float) -3, "\000\000@\300", '0000040c'],
+ [self::FLOAT_TYPE, (float) -2, "\000\000\000\300", '0000000c'],
+ [self::FLOAT_TYPE, (float) -1, "\000\000\200\277", '000008fb'],
+ [self::FLOAT_TYPE, (float) 0, "\000\000\000\000", '00000000'],
+ [self::FLOAT_TYPE, (float) 1, "\000\000\200?", '000008f3'],
+ [self::FLOAT_TYPE, (float) 2, "\000\000\000@", '00000004'],
+ [self::FLOAT_TYPE, (float) 3, "\000\000@@", '00000404'],
+ [self::FLOAT_TYPE, (float) 4, "\000\000\200@", '00000804'],
+ [self::FLOAT_TYPE, (float) 5, "\000\000\240@", '00000a04'],
+ [self::FLOAT_TYPE, (float) 6, "\000\000\300@", '00000c04'],
+ [self::FLOAT_TYPE, (float) 7, "\000\000\340@", '00000e04'],
+ [self::FLOAT_TYPE, (float) 8, "\000\000\000A", '00000014'],
+ [self::FLOAT_TYPE, (float) 9, "\000\000\020A", '00000114'],
+ [self::FLOAT_TYPE, (float) 10, "\000\000 A", '00000214'],
+ [self::FLOAT_TYPE, (float) -1234.5, "\000P\232\304", '0005a94c'],
+ [self::FLOAT_TYPE, (float) -211300000.0, "\352\202I\315", 'ae2894dc'],
+ ];
}
- $decoded_bits_val = call_user_func($decoder, $bits);
- $this->assertEquals($val, $decoded_bits_val,
- sprintf("%s\n expected: '%f'\n given: '%f'",
- 'DECODED BITS', $val, $decoded_bits_val));
-
- $encoded_val_bits = call_user_func($encoder, $val);
- $this->assertEquals($bits, $encoded_val_bits,
- sprintf("%s\n expected: '%s'\n given: '%s'",
- 'ENCODED VAL',
- AvroDebug::hexString($bits),
- AvroDebug::hexString($encoded_val_bits)));
-
- $round_trip_value = call_user_func($decoder, $encoded_val_bits);
- $this->assertEquals($val, $round_trip_value,
- sprintf("%s\n expected: '%f'\n given: '%f'",
- 'ROUND TRIP BITS', $val, $round_trip_value));
- }
-
- function assert_encode_nan_values($type, $val, $bits)
- {
- if (self::FLOAT_TYPE == $type)
+ public static function float_vals_provider(): array
{
- $decoder = array(AvroIOBinaryDecoder::class, 'intBitsToFloat');
- $encoder = array(AvroIOBinaryEncoder::class, 'floatToIntBits');
+ $array = [];
+
+ foreach (self::normal_vals_provider() as $values) {
+ if (self::FLOAT_TYPE == $values[0]) {
+ $array[] = [$values[0], $values[1], $values[2]];
+ }
+ }
+
+ return $array;
}
- else
+
+ public static function double_vals_provider(): array
{
- $decoder = array(AvroIOBinaryDecoder::class, 'longBitsToDouble');
- $encoder = array(AvroIOBinaryEncoder::class, 'doubleToLongBits');
+ $array = [];
+
+ foreach (self::normal_vals_provider() as $values) {
+ if (self::DOUBLE_TYPE === $values[0]) {
+ $array[] = [$values[0], $values[1], $values[2]];
+ }
+ }
+
+ return $array;
}
- $decoded_bits_val = call_user_func($decoder, $bits);
- $this->assertTrue(is_nan($decoded_bits_val),
- sprintf("%s\n expected: '%f'\n given: '%f'",
- 'DECODED BITS', $val, $decoded_bits_val));
-
- $encoded_val_bits = call_user_func($encoder, $val);
- $this->assertEquals($bits, $encoded_val_bits,
- sprintf("%s\n expected: '%s'\n given: '%s'",
- 'ENCODED VAL',
- AvroDebug::hexString($bits),
- AvroDebug::hexString($encoded_val_bits)));
-
- $round_trip_value = call_user_func($decoder, $encoded_val_bits);
- $this->assertTrue(is_nan($round_trip_value),
- sprintf("%s\n expected: '%f'\n given: '%f'",
- 'ROUND TRIP BITS', $val, $round_trip_value));
- }
+ #[DataProvider('float_vals_provider')]
+ public function test_encoding_float_values(string $type, $val, $bits): void
+ {
+ $this->assert_encode_values($type, $val, $bits);
+ }
+
+ #[DataProvider('double_vals_provider')]
+ public function test_encoding_double_values($type, $val, $bits): void
+ {
+ $this->assert_encode_values($type, $val, $bits);
+ }
+
+ public function assert_encode_values(string $type, $val, $bits): void
+ {
+ if (self::FLOAT_TYPE === $type) {
+ $decoder = [AvroIOBinaryDecoder::class, 'intBitsToFloat'];
+ $encoder = [AvroIOBinaryEncoder::class, 'floatToIntBits'];
+ } else {
+ $decoder = [AvroIOBinaryDecoder::class, 'longBitsToDouble'];
+ $encoder = [AvroIOBinaryEncoder::class, 'doubleToLongBits'];
+ }
+
+ $decoded_bits_val = call_user_func($decoder, $bits);
+ $this->assertEquals(
+ $val,
+ $decoded_bits_val,
+ sprintf(
+ "%s\n expected: '%f'\n given: '%f'",
+ 'DECODED BITS',
+ $val,
+ $decoded_bits_val
+ )
+ );
+
+ $encoded_val_bits = call_user_func($encoder, $val);
+ $this->assertEquals(
+ $bits,
+ $encoded_val_bits,
+ sprintf(
+ "%s\n expected: '%s'\n given: '%s'",
+ 'ENCODED VAL',
+ AvroDebug::hexString($bits),
+ AvroDebug::hexString($encoded_val_bits)
+ )
+ );
+
+ $round_trip_value = call_user_func($decoder, $encoded_val_bits);
+ $this->assertEquals(
+ $val,
+ $round_trip_value,
+ sprintf(
+ "%s\n expected: '%f'\n given: '%f'",
+ 'ROUND TRIP BITS',
+ $val,
+ $round_trip_value
+ )
+ );
+ }
+
+ public function assert_encode_nan_values(string $type, $val, $bits): void
+ {
+ if (self::FLOAT_TYPE === $type) {
+ $decoder = [AvroIOBinaryDecoder::class, 'intBitsToFloat'];
+ $encoder = [AvroIOBinaryEncoder::class, 'floatToIntBits'];
+ } else {
+ $decoder = [AvroIOBinaryDecoder::class, 'longBitsToDouble'];
+ $encoder = [AvroIOBinaryEncoder::class, 'doubleToLongBits'];
+ }
+
+ $decoded_bits_val = call_user_func($decoder, $bits);
+ $this->assertTrue(
+ is_nan($decoded_bits_val),
+ sprintf(
+ "%s\n expected: '%f'\n given: '%f'",
+ 'DECODED BITS',
+ $val,
+ $decoded_bits_val
+ )
+ );
+
+ $encoded_val_bits = call_user_func($encoder, $val);
+ $this->assertEquals(
+ $bits,
+ $encoded_val_bits,
+ sprintf(
+ "%s\n expected: '%s'\n given: '%s'",
+ 'ENCODED VAL',
+ AvroDebug::hexString($bits),
+ AvroDebug::hexString($encoded_val_bits)
+ )
+ );
+
+ $round_trip_value = call_user_func($decoder, $encoded_val_bits);
+ $this->assertTrue(
+ is_nan($round_trip_value),
+ sprintf(
+ "%s\n expected: '%f'\n given: '%f'",
+ 'ROUND TRIP BITS',
+ $val,
+ $round_trip_value
+ )
+ );
+ }
}
diff --git a/lang/php/test/IODatumReaderTest.php b/lang/php/test/IODatumReaderTest.php
index 0135751d80c..abb51507c3e 100644
--- a/lang/php/test/IODatumReaderTest.php
+++ b/lang/php/test/IODatumReaderTest.php
@@ -1,4 +1,5 @@
assertTrue(AvroIODatumReader::schemasMatch(
- AvroSchema::parse($writers_schema),
- AvroSchema::parse($readers_schema)));
+ AvroSchema::parse($writersSchema),
+ AvroSchema::parse($readersSchema)
+ ));
}
public function test_aliased(): void
{
$writers_schema = AvroSchema::parse(
<<assertEquals(['field2' => 1], $record);
}
- public function testRecordNullField(): void
+ public function test_record_null_field(): void
{
$schema_json = << 1);
+ $datum = ["one" => 1];
$io = new AvroStringIO();
$writer = new AvroIODatumWriter($schema);
@@ -103,25 +152,25 @@ public function testRecordNullField(): void
$writer->write($datum, $encoder);
$bin = $io->string();
- $this->assertSame('0200', bin2hex($bin));
+ $this->assertSame('0200', bin2hex((string) $bin));
}
- public function testRecordFieldWithDefault(): void
+ public function test_record_field_with_default(): void
{
$schema = AvroSchema::parse(
<<assertEquals(['field1' => "foobar"], $record);
}
- public function testRecordWithLogicalTypes(): void
+ public function test_record_with_logical_types(): void
{
$schema = AvroSchema::parse(
<<projection = AvroSchema::parse($this->projection_json);
}
- public function file_name_provider()
+ public static function file_name_provider(): array
{
$data_dir = AVRO_BUILD_DATA_DIR;
- $data_files = array();
+ $data_files = [];
if (!($dh = opendir($data_dir))) {
- die("Could not open data dir '$data_dir'\n");
+ exit("Could not open data dir '$data_dir'\n");
}
while ($file = readdir($dh)) {
if (preg_match('/^[a-z]+(_deflate|_snappy|_zstandard|_bzip2)?\.avro$/', $file)) {
- $data_files [] = implode(DIRECTORY_SEPARATOR, array($data_dir, $file));
- } else if (preg_match('/[^.]/', $file)) {
+ $data_files[] = implode(DIRECTORY_SEPARATOR, [$data_dir, $file]);
+ } elseif (preg_match('/[^.]/', $file)) {
echo "Skipped: $data_dir/$file", PHP_EOL;
}
}
closedir($dh);
- $ary = array();
+ $ary = [];
foreach ($data_files as $df) {
echo "Reading: $df", PHP_EOL;
- $ary [] = array($df);
+ $ary[] = [$df];
}
+
return $ary;
}
- /**
- * @coversNothing
- * @dataProvider file_name_provider
- */
- public function test_read($file_name)
+ #[DataProvider('file_name_provider')]
+ public function test_read($file_name): void
{
$dr = AvroDataIO::openFile(
- $file_name, AvroFile::READ_MODE, $this->projection_json);
+ $file_name,
+ AvroFile::READ_MODE,
+ $this->projection_json
+ );
$data = $dr->data();
$this->assertNotCount(0, $data, sprintf("no data read from %s", $file_name));
- foreach ($data as $idx => $datum) {
+ foreach ($data as $datum) {
$this->assertNotNull($datum, sprintf("null datum from %s", $file_name));
}
}
diff --git a/lang/php/test/LongEncodingTest.php b/lang/php/test/LongEncodingTest.php
index da4e4c81674..7259c7f9fe3 100644
--- a/lang/php/test/LongEncodingTest.php
+++ b/lang/php/test/LongEncodingTest.php
@@ -1,4 +1,5 @@
skip_64_bit_test_on_32_bit();
- $lval = (int) ((int) $val << $shift);
- $this->assert_bit_shift($expected_lval, strval($lval),
- 'lshift', $lbin, decbin($lval));
+ $lval = ((int) $val << $shift);
+ $this->assert_bit_shift(
+ expected: $expected_lval,
+ actual: (string) $lval,
+ shift_type: 'lshift',
+ expected_binary: $lbin,
+ actual_binary: decbin($lval)
+ );
$rval = ((int) $val >> $shift);
- $this->assert_bit_shift($expected_rval, strval($rval),
- 'rshift', $rbin, decbin($rval));
+ $this->assert_bit_shift(
+ expected: $expected_rval,
+ actual: (string) $rval,
+ shift_type: 'rshift',
+ expected_binary: $rbin,
+ actual_binary: decbin($rval)
+ );
}
- function skip_64_bit_test_on_32_bit()
+ public function skip_64_bit_test_on_32_bit(): void
{
if (!self::is_64_bit()) {
$this->markTestSkipped('Requires 64-bit platform');
}
}
- static function is_64_bit()
+ public static function is_64_bit(): bool
{
- return (PHP_INT_SIZE == 8);
+ return PHP_INT_SIZE === 8;
}
- function assert_bit_shift(
+ public function assert_bit_shift(
$expected,
$actual,
$shift_type,
$expected_binary,
$actual_binary
- ) {
+ ): void {
$this->assertEquals(
- $expected, $actual,
- sprintf("%s\nexpected: %d\n actual: %d\nexpected b: %s\n actual b: %s",
- $shift_type, $expected, $actual,
- $expected_binary, $actual_binary));
+ $expected,
+ $actual,
+ sprintf(
+ "%s\nexpected: %d\n actual: %d\nexpected b: %s\n actual b: %s",
+ $shift_type,
+ $expected,
+ $actual,
+ $expected_binary,
+ $actual_binary
+ )
+ );
}
- /**
- * @dataProvider bit_shift_provider
- */
- function test_left_shift_gmp(
- $val,
- $shift,
- $expected_lval,
- $expected_rval,
- $lbin,
- $rbin
- ) {
+ #[DataProvider('bit_shift_provider')]
+ public function test_left_shift_gmp(
+ string $val,
+ int $shift,
+ string $expected_lval,
+ string $expected_rval,
+ string $lbin,
+ string $rbin
+ ): void {
$this->skip_if_no_gmp();
$lval = gmp_strval(AvroGMP::shiftLeft($val, $shift));
- $this->assert_bit_shift($expected_lval, $lval, 'gmp left shift',
- $lbin, decbin((int) $lval));
+ $this->assert_bit_shift(
+ $expected_lval,
+ $lval,
+ 'gmp left shift',
+ $lbin,
+ decbin((int) $lval)
+ );
}
- function skip_if_no_gmp()
+ public function skip_if_no_gmp(): void
{
if (!extension_loaded('gmp')) {
$this->markTestSkipped('Requires GMP PHP Extension.');
}
}
- /**
- * @dataProvider bit_shift_provider
- */
- function test_right_shift_gmp(
- $val,
- $shift,
- $expected_lval,
- $expected_rval,
- $lbin,
- $rbin
- ) {
+ #[DataProvider('bit_shift_provider')]
+ public function test_right_shift_gmp(
+ string $val,
+ int $shift,
+ string $expected_lval,
+ string $expected_rval,
+ string $lbin,
+ string $rbin
+ ): void {
$this->skip_if_no_gmp();
$rval = gmp_strval(AvroGMP::shiftRight($val, $shift));
- $this->assert_bit_shift($expected_rval, $rval, 'gmp right shift',
- $rbin, decbin((int) $rval));
+ $this->assert_bit_shift(
+ $expected_rval,
+ $rval,
+ 'gmp right shift',
+ $rbin,
+ decbin((int) $rval)
+ );
}
- /**
- * @dataProvider long_provider
- */
- function test_encode_long($val, $expected_bytes)
+ #[DataProvider('long_provider')]
+ public function test_encode_long(string $val, string $expected_bytes): void
{
$this->skip_64_bit_test_on_32_bit();
$bytes = AvroIOBinaryEncoder::encodeLong($val);
$this->assertEquals($expected_bytes, $bytes);
}
- /**
- * @dataProvider long_provider
- */
- function test_gmp_encode_long($val, $expected_bytes)
+ #[DataProvider('long_provider')]
+ public function test_gmp_encode_long(string $val, string $expected_bytes): void
{
$this->skip_if_no_gmp();
$bytes = AvroGMP::encodeLong($val);
$this->assertEquals($expected_bytes, $bytes);
}
- /**
- * @dataProvider long_provider
- */
- function test_decode_long_from_array($expected_val, $bytes)
+ #[DataProvider('long_provider')]
+ public function test_decode_long_from_array(string $expected_val, string $bytes): void
{
$this->skip_64_bit_test_on_32_bit();
- $ary = array_map('ord', str_split($bytes));
+ $ary = array_map(ord(...), str_split($bytes));
$val = AvroIOBinaryDecoder::decodeLongFromArray($ary);
$this->assertEquals($expected_val, $val);
}
- /**
- * @dataProvider long_provider
- */
- function test_gmp_decode_long_from_array($expected_val, $bytes)
+ #[DataProvider('long_provider')]
+ public function test_gmp_decode_long_from_array(string $expected_val, string $bytes): void
{
$this->skip_if_no_gmp();
- $ary = array_map('ord', str_split($bytes));
+ $ary = array_map(ord(...), str_split($bytes));
$val = AvroGMP::decodeLongFromArray($ary);
$this->assertEquals($expected_val, $val);
}
- function long_provider()
+ public static function long_provider()
{
return [
['0', "\x0"],
@@ -170,12 +191,12 @@ function long_provider()
['-7', "\xd"],
['-10000', "\x9f\x9c\x1"],
['-2147483648', "\xff\xff\xff\xff\xf"],
- ['-98765432109', "\xd9\x94\x87\xee\xdf\x5"]
+ ['-98765432109', "\xd9\x94\x87\xee\xdf\x5"],
];
}
- function bit_shift_provider()
+ public static function bit_shift_provider()
{
// val shift lval rval
return [
@@ -185,7 +206,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'0',
@@ -193,7 +214,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'0',
@@ -201,7 +222,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'0',
@@ -209,7 +230,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'1',
@@ -217,7 +238,7 @@ function bit_shift_provider()
'1',
'1',
'1',
- '1'
+ '1',
],
[
'1',
@@ -225,7 +246,7 @@ function bit_shift_provider()
'2',
'0',
'10',
- '0'
+ '0',
],
[
'1',
@@ -233,7 +254,7 @@ function bit_shift_provider()
'128',
'0',
'10000000',
- '0'
+ '0',
],
[
'1',
@@ -241,7 +262,7 @@ function bit_shift_provider()
'-9223372036854775808',
'0',
'1000000000000000000000000000000000000000000000000000000000000000',
- '0'
+ '0',
],
[
'100',
@@ -249,7 +270,7 @@ function bit_shift_provider()
'100',
'100',
'1100100',
- '1100100'
+ '1100100',
],
[
'100',
@@ -257,7 +278,7 @@ function bit_shift_provider()
'200',
'50',
'11001000',
- '110010'
+ '110010',
],
[
'100',
@@ -265,7 +286,7 @@ function bit_shift_provider()
'12800',
'0',
'11001000000000',
- '0'
+ '0',
],
[
'100',
@@ -273,7 +294,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'1000000',
@@ -281,7 +302,7 @@ function bit_shift_provider()
'1000000',
'1000000',
'11110100001001000000',
- '11110100001001000000'
+ '11110100001001000000',
],
[
'1000000',
@@ -289,7 +310,7 @@ function bit_shift_provider()
'2000000',
'500000',
'111101000010010000000',
- '1111010000100100000'
+ '1111010000100100000',
],
[
'1000000',
@@ -297,7 +318,7 @@ function bit_shift_provider()
'128000000',
'7812',
'111101000010010000000000000',
- '1111010000100'
+ '1111010000100',
],
[
'1000000',
@@ -305,7 +326,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'2147483647',
@@ -313,7 +334,7 @@ function bit_shift_provider()
'2147483647',
'2147483647',
'1111111111111111111111111111111',
- '1111111111111111111111111111111'
+ '1111111111111111111111111111111',
],
[
'2147483647',
@@ -321,7 +342,7 @@ function bit_shift_provider()
'4294967294',
'1073741823',
'11111111111111111111111111111110',
- '111111111111111111111111111111'
+ '111111111111111111111111111111',
],
[
'2147483647',
@@ -329,7 +350,7 @@ function bit_shift_provider()
'274877906816',
'16777215',
'11111111111111111111111111111110000000',
- '111111111111111111111111'
+ '111111111111111111111111',
],
[
'2147483647',
@@ -337,7 +358,7 @@ function bit_shift_provider()
'-9223372036854775808',
'0',
'1000000000000000000000000000000000000000000000000000000000000000',
- '0'
+ '0',
],
[
'10000000000',
@@ -345,7 +366,7 @@ function bit_shift_provider()
'10000000000',
'10000000000',
'1001010100000010111110010000000000',
- '1001010100000010111110010000000000'
+ '1001010100000010111110010000000000',
],
[
'10000000000',
@@ -353,7 +374,7 @@ function bit_shift_provider()
'20000000000',
'5000000000',
'10010101000000101111100100000000000',
- '100101010000001011111001000000000'
+ '100101010000001011111001000000000',
],
[
'10000000000',
@@ -361,7 +382,7 @@ function bit_shift_provider()
'1280000000000',
'78125000',
'10010101000000101111100100000000000000000',
- '100101010000001011111001000'
+ '100101010000001011111001000',
],
[
'10000000000',
@@ -369,7 +390,7 @@ function bit_shift_provider()
'0',
'0',
'0',
- '0'
+ '0',
],
[
'9223372036854775807',
@@ -377,7 +398,7 @@ function bit_shift_provider()
'9223372036854775807',
'9223372036854775807',
'111111111111111111111111111111111111111111111111111111111111111',
- '111111111111111111111111111111111111111111111111111111111111111'
+ '111111111111111111111111111111111111111111111111111111111111111',
],
[
'9223372036854775807',
@@ -385,7 +406,7 @@ function bit_shift_provider()
'-2',
'4611686018427387903',
'1111111111111111111111111111111111111111111111111111111111111110',
- '11111111111111111111111111111111111111111111111111111111111111'
+ '11111111111111111111111111111111111111111111111111111111111111',
],
[
'9223372036854775807',
@@ -393,7 +414,7 @@ function bit_shift_provider()
'-128',
'72057594037927935',
'1111111111111111111111111111111111111111111111111111111110000000',
- '11111111111111111111111111111111111111111111111111111111'
+ '11111111111111111111111111111111111111111111111111111111',
],
[
'9223372036854775807',
@@ -401,7 +422,7 @@ function bit_shift_provider()
'-9223372036854775808',
'0',
'1000000000000000000000000000000000000000000000000000000000000000',
- '0'
+ '0',
],
[
'-1',
@@ -409,7 +430,7 @@ function bit_shift_provider()
'-1',
'-1',
'1111111111111111111111111111111111111111111111111111111111111111',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-1',
@@ -417,7 +438,7 @@ function bit_shift_provider()
'-2',
'-1',
'1111111111111111111111111111111111111111111111111111111111111110',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-1',
@@ -425,7 +446,7 @@ function bit_shift_provider()
'-128',
'-1',
'1111111111111111111111111111111111111111111111111111111110000000',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-1',
@@ -433,7 +454,7 @@ function bit_shift_provider()
'-9223372036854775808',
'-1',
'1000000000000000000000000000000000000000000000000000000000000000',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-100',
@@ -441,7 +462,7 @@ function bit_shift_provider()
'-100',
'-100',
'1111111111111111111111111111111111111111111111111111111110011100',
- '1111111111111111111111111111111111111111111111111111111110011100'
+ '1111111111111111111111111111111111111111111111111111111110011100',
],
[
'-100',
@@ -449,7 +470,7 @@ function bit_shift_provider()
'-200',
'-50',
'1111111111111111111111111111111111111111111111111111111100111000',
- '1111111111111111111111111111111111111111111111111111111111001110'
+ '1111111111111111111111111111111111111111111111111111111111001110',
],
[
'-100',
@@ -457,7 +478,7 @@ function bit_shift_provider()
'-12800',
'-1',
'1111111111111111111111111111111111111111111111111100111000000000',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-100',
@@ -465,7 +486,7 @@ function bit_shift_provider()
'0',
'-1',
'0',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-1000000',
@@ -473,7 +494,7 @@ function bit_shift_provider()
'-1000000',
'-1000000',
'1111111111111111111111111111111111111111111100001011110111000000',
- '1111111111111111111111111111111111111111111100001011110111000000'
+ '1111111111111111111111111111111111111111111100001011110111000000',
],
[
'-1000000',
@@ -481,7 +502,7 @@ function bit_shift_provider()
'-2000000',
'-500000',
'1111111111111111111111111111111111111111111000010111101110000000',
- '1111111111111111111111111111111111111111111110000101111011100000'
+ '1111111111111111111111111111111111111111111110000101111011100000',
],
[
'-1000000',
@@ -489,7 +510,7 @@ function bit_shift_provider()
'-128000000',
'-7813',
'1111111111111111111111111111111111111000010111101110000000000000',
- '1111111111111111111111111111111111111111111111111110000101111011'
+ '1111111111111111111111111111111111111111111111111110000101111011',
],
[
'-1000000',
@@ -497,7 +518,7 @@ function bit_shift_provider()
'0',
'-1',
'0',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-2147483648',
@@ -505,7 +526,7 @@ function bit_shift_provider()
'-2147483648',
'-2147483648',
'1111111111111111111111111111111110000000000000000000000000000000',
- '1111111111111111111111111111111110000000000000000000000000000000'
+ '1111111111111111111111111111111110000000000000000000000000000000',
],
[
'-2147483648',
@@ -513,7 +534,7 @@ function bit_shift_provider()
'-4294967296',
'-1073741824',
'1111111111111111111111111111111100000000000000000000000000000000',
- '1111111111111111111111111111111111000000000000000000000000000000'
+ '1111111111111111111111111111111111000000000000000000000000000000',
],
[
'-2147483648',
@@ -521,7 +542,7 @@ function bit_shift_provider()
'-274877906944',
'-16777216',
'1111111111111111111111111100000000000000000000000000000000000000',
- '1111111111111111111111111111111111111111000000000000000000000000'
+ '1111111111111111111111111111111111111111000000000000000000000000',
],
[
'-2147483648',
@@ -529,7 +550,7 @@ function bit_shift_provider()
'0',
'-1',
'0',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-10000000000',
@@ -537,7 +558,7 @@ function bit_shift_provider()
'-10000000000',
'-10000000000',
'1111111111111111111111111111110110101011111101000001110000000000',
- '1111111111111111111111111111110110101011111101000001110000000000'
+ '1111111111111111111111111111110110101011111101000001110000000000',
],
[
'-10000000000',
@@ -545,7 +566,7 @@ function bit_shift_provider()
'-20000000000',
'-5000000000',
'1111111111111111111111111111101101010111111010000011100000000000',
- '1111111111111111111111111111111011010101111110100000111000000000'
+ '1111111111111111111111111111111011010101111110100000111000000000',
],
[
'-10000000000',
@@ -553,7 +574,7 @@ function bit_shift_provider()
'-1280000000000',
'-78125000',
'1111111111111111111111101101010111111010000011100000000000000000',
- '1111111111111111111111111111111111111011010101111110100000111000'
+ '1111111111111111111111111111111111111011010101111110100000111000',
],
[
'-10000000000',
@@ -561,7 +582,7 @@ function bit_shift_provider()
'0',
'-1',
'0',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
[
'-9223372036854775808',
@@ -569,7 +590,7 @@ function bit_shift_provider()
'-9223372036854775808',
'-9223372036854775808',
'1000000000000000000000000000000000000000000000000000000000000000',
- '1000000000000000000000000000000000000000000000000000000000000000'
+ '1000000000000000000000000000000000000000000000000000000000000000',
],
[
'-9223372036854775808',
@@ -577,7 +598,7 @@ function bit_shift_provider()
'0',
'-4611686018427387904',
'0',
- '1100000000000000000000000000000000000000000000000000000000000000'
+ '1100000000000000000000000000000000000000000000000000000000000000',
],
[
'-9223372036854775808',
@@ -585,7 +606,7 @@ function bit_shift_provider()
'0',
'-72057594037927936',
'0',
- '1111111100000000000000000000000000000000000000000000000000000000'
+ '1111111100000000000000000000000000000000000000000000000000000000',
],
[
'-9223372036854775808',
@@ -593,7 +614,7 @@ function bit_shift_provider()
'0',
'-1',
'0',
- '1111111111111111111111111111111111111111111111111111111111111111'
+ '1111111111111111111111111111111111111111111111111111111111111111',
],
];
}
diff --git a/lang/php/test/NameTest.php b/lang/php/test/NameTest.php
index 7ecc0d8f582..059b0976808 100644
--- a/lang/php/test/NameTest.php
+++ b/lang/php/test/NameTest.php
@@ -1,4 +1,5 @@
name = $name;
- $this->namespace = $namespace;
- $this->default_namespace = $default_namespace;
- $this->is_valid = $is_valid;
- $this->expected_fullname = $expected_fullname;
+ public function __construct(public $name, public $namespace, public $default_namespace, public $is_valid, public $expected_fullname = null)
+ {
}
- function __toString()
+ public function __toString(): string
{
return var_export($this, true);
}
@@ -53,10 +39,9 @@ function __toString()
class NameTest extends TestCase
{
-
- function fullname_provider()
+ public static function fullname_provider(): array
{
- $examples = array(
+ $examples = [
new NameExample('foo', null, null, true, 'foo'),
new NameExample('foo', 'bar', null, true, 'bar.foo'),
new NameExample('bar.foo', 'baz', null, true, 'bar.foo'),
@@ -68,32 +53,33 @@ function fullname_provider()
new NameExample('bar.f0o', 'baz', null, true, 'bar.f0o'),
new NameExample(' .foo', 'baz', null, false),
new NameExample('bar. foo', 'baz', null, false),
- new NameExample('bar. ', 'baz', null, false)
- );
- $exes = array();
+ new NameExample('bar. ', 'baz', null, false),
+ ];
+ $exes = [];
foreach ($examples as $ex) {
- $exes [] = array($ex);
+ $exes[] = [$ex];
}
+
return $exes;
}
- /**
- * @dataProvider fullname_provider
- */
- function test_fullname($ex)
+ #[DataProvider('fullname_provider')]
+ public function test_fullname($ex): void
{
try {
$name = new AvroName($ex->name, $ex->namespace, $ex->default_namespace);
$this->assertTrue($ex->is_valid);
$this->assertEquals($ex->expected_fullname, $name->fullname());
} catch (AvroSchemaParseException $e) {
- $this->assertFalse($ex->is_valid, sprintf("%s:\n%s",
+ $this->assertFalse($ex->is_valid, sprintf(
+ "%s:\n%s",
$ex,
- $e->getMessage()));
+ $e->getMessage()
+ ));
}
}
- function name_provider()
+ public static function name_provider(): array
{
return [
['a', true],
@@ -102,14 +88,12 @@ function name_provider()
['', false],
[null, false],
[' ', false],
- ['Cons', true]
+ ['Cons', true],
];
}
- /**
- * @dataProvider name_provider
- */
- function test_name($name, $is_well_formed)
+ #[DataProvider('name_provider')]
+ public function test_name($name, $is_well_formed): void
{
$this->assertEquals(AvroName::isWellFormedName($name), $is_well_formed);
}
diff --git a/lang/php/test/ProtocolFileTest.php b/lang/php/test/ProtocolFileTest.php
index fd24cc32b46..fcb276fee63 100644
--- a/lang/php/test/ProtocolFileTest.php
+++ b/lang/php/test/ProtocolFileTest.php
@@ -1,4 +1,5 @@
prot_parseable);
- for ($i = 0; $i < $cnt; $i++) {
- try {
- //print($i . " " . ($this->prot_parseable[$i]?"true":"false") . " \n");
- $prot = AvroProtocol::parse($this->prot_data[$i]);
- } catch (AvroSchemaParseException $x) {
- // exception ok if we expected this protocol spec to be unparseable
- $this->assertEquals(false, $this->prot_parseable[$i]);
- }
+ try {
+ AvroProtocol::parse($jsonSchema);
+ self::assertTrue($expectedResult);
+ } catch (AvroSchemaParseException) {
+ // exception ok if we expected this protocol spec to be unparseable
+ self::assertFalse($expectedResult);
}
}
}
diff --git a/lang/php/test/SchemaTest.php b/lang/php/test/SchemaTest.php
index e0d7be75b07..e1ab5a10adb 100644
--- a/lang/php/test/SchemaTest.php
+++ b/lang/php/test/SchemaTest.php
@@ -1,4 +1,5 @@
schema_string = $schema_string;
- $this->is_valid = $is_valid;
- $this->name = $name ? $name : $schema_string;
- $this->normalized_schema_string = $normalized_schema_string
- ? $normalized_schema_string : json_encode(json_decode($schema_string, true));
- $this->comment = $comment;
+ $this->name = $name ?: $this->schema_string;
+ $this->normalized_schema_string = $normalized_schema_string ?: json_encode(json_decode((string) $this->schema_string, true));
}
}
@@ -61,8 +56,10 @@ public function test_json_decode(): void
$this->assertEquals(["foo" => 27], (array) json_decode('{"foo": 27}'));
$this->assertIsArray(json_decode('{"foo": 27}', true));
$this->assertEquals(["foo" => 27], json_decode('{"foo": 27}', true));
- $this->assertEquals(["bar", "baz", "blurfl"],
- json_decode('["bar", "baz", "blurfl"]', true));
+ $this->assertEquals(
+ ["bar", "baz", "blurfl"],
+ json_decode('["bar", "baz", "blurfl"]', true)
+ );
$this->assertIsNotArray(json_decode('null', true));
$this->assertEquals(["type" => 'null'], json_decode('{"type": "null"}', true));
@@ -73,31 +70,325 @@ public function test_json_decode(): void
$this->assertEquals('boolean', json_decode('"boolean"'));
}
- public function schema_examples_provider(): array
+ public static function schema_examples_provider(): array
{
self::make_examples();
$ary = [];
foreach (self::$examples as $example) {
$ary[] = [$example];
}
+
return $ary;
}
+ #[DataProvider('schema_examples_provider')]
+ public function test_parse($example): void
+ {
+ $schema_string = $example->schema_string;
+
+ try {
+ $normalized_schema_string = $example->normalized_schema_string;
+ $schema = AvroSchema::parse($schema_string);
+ $this->assertTrue(
+ $example->is_valid,
+ sprintf(
+ "schema_string: %s\n",
+ $schema_string
+ )
+ );
+ $this->assertEquals($normalized_schema_string, (string) $schema);
+ } catch (AvroSchemaParseException $e) {
+ $this->assertFalse(
+ $example->is_valid,
+ sprintf(
+ "schema_string: %s\n%s",
+ $schema_string,
+ $e->getMessage()
+ )
+ );
+ }
+ }
+
+ public function test_to_avro_includes_aliases(): void
+ {
+ $hash = <<assertEquals($schema->toAvro(), json_decode($hash, true));
+ }
+
+ public function test_validate_field_aliases(): void
+ {
+ $this->expectException(AvroSchemaParseException::class);
+ $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
+ AvroSchema::parse(
+ <<expectException(AvroSchemaParseException::class);
+ $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
+ AvroSchema::parse(
+ <<expectException(AvroSchemaParseException::class);
+ $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
+ AvroSchema::parse(
+ <<expectException(AvroSchemaParseException::class);
+ $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
+ AvroSchema::parse(<<expectException(AvroSchemaParseException::class);
+ $this->expectExceptionMessage('Alias already in use');
+ AvroSchema::parse(<<expectNotToPerformAssertions();
+ AvroSchema::parse(
+ <<toAvro(), json_decode($avro, true));
+ }
+
+ public static function invalidDecimalLogicalTypeDataProvider(): array
+ {
+ return [
+ 'bytes - invalid precision' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": -1, "scale": 2}',
+ new AvroException("Precision '-1' is invalid. It must be a positive integer."),
+ ],
+ 'bytes - invalid value for precision (float)' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": 11.23, "scale": 2}',
+ new AvroException("Invalid value '11.23' for 'precision' attribute of decimal logical type."),
+ ],
+ 'bytes - invalid value for precision (string)' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": "banana", "scale": 2}',
+ new AvroException("Invalid value 'banana' for 'precision' attribute of decimal logical type."),
+ ],
+ 'bytes - invalid scale' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": -1}',
+ new AvroException("Scale '-1' is invalid. It must be a non-negative integer."),
+ ],
+ 'bytes - invalid scale for precision' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": 2}',
+ new AvroException("Scale must be a lower than precision (scale='2', precision='2')."),
+ ],
+ 'bytes - invalid value for scale (float)' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": 9.12}',
+ new AvroException("Invalid value '9.12' for 'scale' attribute of decimal logical type."),
+ ],
+ 'bytes - invalid value for scale (string)' => [
+ '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": "two"}',
+ new AvroException("Invalid value 'two' for 'scale' attribute of decimal logical type."),
+ ],
+ 'fixed - invalid precision' => [
+ '{"name": "fixed_decimal", "type": "fixed", "logicalType": "decimal", "size": 2, "precision": -1, "scale": 2}',
+ new AvroException("Precision '-1' is invalid. It must be a positive integer."),
+ ],
+ 'fixed - invalid value for precision with specified size' => [
+ '{"name": "fixed_decimal", "type": "fixed", "logicalType": "decimal", "size": 2, "precision": 6, "scale": 2}',
+ new AvroException("Invalid precision for specified fixed size (size='2', precision='6')."),
+ ],
+ ];
+ }
+
+ #[DataProvider('invalidDecimalLogicalTypeDataProvider')]
+ public function test_decimal_logical_type_with_invalid_parameters(string $schema, AvroException $exception): void
+ {
+ $this->expectException($exception::class);
+ $this->expectExceptionMessage($exception->getMessage());
+ AvroSchema::parse($schema);
+ }
+
protected static function make_examples(): void
{
- $primitive_examples = array_merge([
- new SchemaExample('"True"', false),
- new SchemaExample('{"no_type": "test"}', false),
- new SchemaExample('{"type": "panther"}', false)
- ],
- self::make_primitive_examples());
+ $primitive_examples = array_merge(
+ [
+ new SchemaExample('"True"', false),
+ new SchemaExample('{"no_type": "test"}', false),
+ new SchemaExample('{"type": "panther"}', false),
+ ],
+ self::make_primitive_examples()
+ );
$array_examples = [
new SchemaExample('{"type": "array", "items": "long"}', true),
new SchemaExample('
{"type": "array",
"items": {"type": "enum", "name": "Test", "symbols": ["A", "B"]}}
- ', true)
+ ', true),
];
$map_examples = [
@@ -105,7 +396,7 @@ protected static function make_examples(): void
new SchemaExample('
{"type": "map",
"values": {"type": "enum", "name": "Test", "symbols": ["A", "B"]}}
- ', true)
+ ', true),
];
$union_examples = [
@@ -129,7 +420,8 @@ protected static function make_examples(): void
new SchemaExample('["long",
["string", "null"],
"int"]', false),
- new SchemaExample('["null", "boolean", "int", "long", "float", "double",
+ new SchemaExample(
+ '["null", "boolean", "int", "long", "float", "double",
"string", "bytes",
{"type": "array", "items":"int"},
{"type": "map", "values":"int"},
@@ -138,9 +430,12 @@ protected static function make_examples(): void
{"name": "foo", "type":"fixed",
"size":16},
{"name": "baz", "type":"enum", "symbols":["A", "B", "C"]}
- ]', true,
- '["null","boolean","int","long","float","double","string","bytes",{"type":"array","items":"int"},{"type":"map","values":"int"},{"type":"record","name":"bar","fields":[{"name":"label","type":"string"}]},{"type":"fixed","name":"foo","size":16},{"type":"enum","name":"baz","symbols":["A","B","C"]}]'),
- new SchemaExample('
+ ]',
+ true,
+ '["null","boolean","int","long","float","double","string","bytes",{"type":"array","items":"int"},{"type":"map","values":"int"},{"type":"record","name":"bar","fields":[{"name":"label","type":"string"}]},{"type":"fixed","name":"foo","size":16},{"type":"enum","name":"baz","symbols":["A","B","C"]}]'
+ ),
+ new SchemaExample(
+ '
[{"name":"subtract", "namespace":"com.example",
"type":"record",
"fields":[{"name":"minuend", "type":"int"},
@@ -150,8 +445,10 @@ protected static function make_examples(): void
"fields":[{"name":"quotient", "type":"int"},
{"name":"dividend", "type":"int"}]},
{"type": "array", "items": "string"}]
- ', true,
- '[{"type":"record","name":"subtract","namespace":"com.example","fields":[{"name":"minuend","type":"int"},{"name":"subtrahend","type":"int"}]},{"type":"record","name":"divide","namespace":"com.example","fields":[{"name":"quotient","type":"int"},{"name":"dividend","type":"int"}]},{"type":"array","items":"string"}]'),
+ ',
+ true,
+ '[{"type":"record","name":"subtract","namespace":"com.example","fields":[{"name":"minuend","type":"int"},{"name":"subtrahend","type":"int"}]},{"type":"record","name":"divide","namespace":"com.example","fields":[{"name":"quotient","type":"int"},{"name":"dividend","type":"int"}]},{"type":"array","items":"string"}]'
+ ),
];
$fixed_examples = [
@@ -170,32 +467,48 @@ protected static function make_examples(): void
{"type": "fixed",
"size": 314}
', false),
- new SchemaExample('{"type":"fixed","name":"ex","doc":"this should be ignored","size": 314}',
+ new SchemaExample(
+ '{"type":"fixed","name":"ex","doc":"this should be ignored","size": 314}',
true,
- '{"type":"fixed","name":"ex","size":314}'),
- new SchemaExample('{"name": "bar",
+ '{"type":"fixed","name":"ex","size":314}'
+ ),
+ new SchemaExample(
+ '{"name": "bar",
"namespace": "com.example",
"type": "fixed",
- "size": 32 }', true,
- '{"type":"fixed","name":"bar","namespace":"com.example","size":32}'),
- new SchemaExample('{"name": "com.example.bar",
+ "size": 32 }',
+ true,
+ '{"type":"fixed","name":"bar","namespace":"com.example","size":32}'
+ ),
+ new SchemaExample(
+ '{"name": "com.example.bar",
"type": "fixed",
- "size": 32 }', true,
- '{"type":"fixed","name":"bar","namespace":"com.example","size":32}')
+ "size": 32 }',
+ true,
+ '{"type":"fixed","name":"bar","namespace":"com.example","size":32}'
+ ),
];
- $fixed_examples [] = new SchemaExample(
- '{"type":"fixed","name":"_x.bar","size":4}', true,
- '{"type":"fixed","name":"bar","namespace":"_x","size":4}');
- $fixed_examples [] = new SchemaExample(
- '{"type":"fixed","name":"baz._x","size":4}', true,
- '{"type":"fixed","name":"_x","namespace":"baz","size":4}');
- $fixed_examples [] = new SchemaExample(
- '{"type":"fixed","name":"baz.3x","size":4}', false);
$fixed_examples[] = new SchemaExample(
- '{"type":"fixed", "name":"Fixed2", "aliases":["Fixed1"], "size": 2}', true);
+ '{"type":"fixed","name":"_x.bar","size":4}',
+ true,
+ '{"type":"fixed","name":"bar","namespace":"_x","size":4}'
+ );
+ $fixed_examples[] = new SchemaExample(
+ '{"type":"fixed","name":"baz._x","size":4}',
+ true,
+ '{"type":"fixed","name":"_x","namespace":"baz","size":4}'
+ );
+ $fixed_examples[] = new SchemaExample(
+ '{"type":"fixed","name":"baz.3x","size":4}',
+ false
+ );
+ $fixed_examples[] = new SchemaExample(
+ '{"type":"fixed", "name":"Fixed2", "aliases":["Fixed1"], "size": 2}',
+ true
+ );
- $enum_examples = array(
+ $enum_examples = [
new SchemaExample('{"type": "enum", "name": "Test", "symbols": ["A", "B"]}', true),
new SchemaExample('
{"type": "enum",
@@ -216,8 +529,10 @@ protected static function make_examples(): void
"name": "Test"
"symbols" : ["AA", "AA"]}
', false),
- new SchemaExample('{"type":"enum","name":"Test","symbols":["AA", 16]}',
- false),
+ new SchemaExample(
+ '{"type":"enum","name":"Test","symbols":["AA", 16]}',
+ false
+ ),
new SchemaExample('
{"type": "enum",
"name": "blood_types",
@@ -229,43 +544,42 @@ protected static function make_examples(): void
"name": "blood-types",
"doc": 16,
"symbols" : ["A", "AB", "B", "O"]}
- ', false)
- );
-
+ ', false),
+ ];
- $record_examples = array();
- $record_examples [] = new SchemaExample('
+ $record_examples = [];
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Test",
"fields": [{"name": "f",
"type": "long"}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "error",
"name": "Test",
"fields": [{"name": "f",
"type": "long"}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Node",
"fields": [{"name": "label", "type": "string"},
{"name": "children",
"type": {"type": "array", "items": "Node"}}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "ListLink",
"fields": [{"name": "car", "type": "int"},
{"name": "cdr", "type": "ListLink"}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Lisp",
"fields": [{"name": "value",
"type": ["null", "string"]}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Lisp",
"fields": [{"name": "value",
@@ -275,7 +589,7 @@ protected static function make_examples(): void
"fields": [{"name": "car", "type": "string"},
{"name": "cdr", "type": "string"}]}]}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Lisp",
"fields": [{"name": "value",
@@ -285,7 +599,7 @@ protected static function make_examples(): void
"fields": [{"name": "car", "type": "Lisp"},
{"name": "cdr", "type": "Lisp"}]}]}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "HandshakeRequest",
"namespace": "org.apache.avro.ipc",
@@ -294,7 +608,7 @@ protected static function make_examples(): void
{"name": "meta",
"type": ["null", {"type": "map", "values": "bytes"}]}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "HandshakeRequest",
"namespace": "org.apache.avro.ipc",
@@ -305,7 +619,8 @@ protected static function make_examples(): void
{"name": "meta",
"type": ["null", {"type": "map", "values": "bytes"}]}]}
', true);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample(
+ '
{"type": "record",
"name": "HandshakeResponse",
"namespace": "org.apache.avro.ipc",
@@ -319,10 +634,12 @@ protected static function make_examples(): void
{"name": "MD5", "size": 16, "type": "fixed"}]},
{"name": "meta",
"type": ["null", {"type": "map", "values": "bytes"}]}]}
- ', true,
+ ',
+ true,
'{"type":"record","name":"HandshakeResponse","namespace":"org.apache.avro.ipc","fields":[{"name":"match","type":{"type":"enum","name":"HandshakeMatch","symbols":["BOTH","CLIENT","NONE"]}},{"name":"serverProtocol","type":["null","string"]},{"name":"serverHash","type":["null",{"type":"fixed","name":"MD5","size":16}]},{"name":"meta","type":["null",{"type":"map","values":"bytes"}]}]}'
);
- $record_examples [] = new SchemaExample('{"type": "record",
+ $record_examples[] = new SchemaExample(
+ '{"type": "record",
"namespace": "org.apache.avro",
"name": "Interop",
"fields": [{"type": {"fields": [{"type": {"items": "org.apache.avro.Node",
@@ -331,9 +648,12 @@ protected static function make_examples(): void
"type": "record",
"name": "Node"},
"name": "recordField"}]}
-', true,
- '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"children","type":{"type":"array","items":"Node"}}]}}]}');
- $record_examples [] = new SchemaExample('{"type": "record",
+',
+ true,
+ '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
+ );
+ $record_examples[] = new SchemaExample(
+ '{"type": "record",
"namespace": "org.apache.avro",
"name": "Interop",
"fields": [{"type": {"symbols": ["A", "B", "C"], "type": "enum", "name": "Kind"},
@@ -343,10 +663,13 @@ protected static function make_examples(): void
"name": "children"}],
"type": "record",
"name": "Node"},
- "name": "recordField"}]}', true,
- '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}');
+ "name": "recordField"}]}',
+ true,
+ '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
+ );
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample(
+ '
{"type": "record",
"name": "Interop",
"namespace": "org.apache.avro",
@@ -383,65 +706,79 @@ protected static function make_examples(): void
{"name": "children",
"type": {"type": "array",
"items": "Node"}}]}}]}
- ', true,
- '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":{"type":"record","name":"Foo","fields":[{"name":"label","type":"string"}]}}},{"name":"unionField","type":["boolean","double",{"type":"array","items":"bytes"}]},{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"fixedField","type":{"type":"fixed","name":"MD5","size":16}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}');
- $record_examples [] = new SchemaExample('{"type": "record", "namespace": "org.apache.avro", "name": "Interop", "fields": [{"type": "int", "name": "intField"}, {"type": "long", "name": "longField"}, {"type": "string", "name": "stringField"}, {"type": "boolean", "name": "boolField"}, {"type": "float", "name": "floatField"}, {"type": "double", "name": "doubleField"}, {"type": "bytes", "name": "bytesField"}, {"type": "null", "name": "nullField"}, {"type": {"items": "double", "type": "array"}, "name": "arrayField"}, {"type": {"type": "map", "values": {"fields": [{"type": "string", "name": "label"}], "type": "record", "name": "Foo"}}, "name": "mapField"}, {"type": ["boolean", "double", {"items": "bytes", "type": "array"}], "name": "unionField"}, {"type": {"symbols": ["A", "B", "C"], "type": "enum", "name": "Kind"}, "name": "enumField"}, {"type": {"type": "fixed", "name": "MD5", "size": 16}, "name": "fixedField"}, {"type": {"fields": [{"type": "string", "name": "label"}, {"type": {"items": "org.apache.avro.Node", "type": "array"}, "name": "children"}], "type": "record", "name": "Node"}, "name": "recordField"}]}
-', true,
- '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":{"type":"record","name":"Foo","fields":[{"name":"label","type":"string"}]}}},{"name":"unionField","type":["boolean","double",{"type":"array","items":"bytes"}]},{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"fixedField","type":{"type":"fixed","name":"MD5","size":16}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}');
- $record_examples [] = new SchemaExample('
+ ',
+ true,
+ '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":{"type":"record","name":"Foo","fields":[{"name":"label","type":"string"}]}}},{"name":"unionField","type":["boolean","double",{"type":"array","items":"bytes"}]},{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"fixedField","type":{"type":"fixed","name":"MD5","size":16}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
+ );
+ $record_examples[] = new SchemaExample(
+ '{"type": "record", "namespace": "org.apache.avro", "name": "Interop", "fields": [{"type": "int", "name": "intField"}, {"type": "long", "name": "longField"}, {"type": "string", "name": "stringField"}, {"type": "boolean", "name": "boolField"}, {"type": "float", "name": "floatField"}, {"type": "double", "name": "doubleField"}, {"type": "bytes", "name": "bytesField"}, {"type": "null", "name": "nullField"}, {"type": {"items": "double", "type": "array"}, "name": "arrayField"}, {"type": {"type": "map", "values": {"fields": [{"type": "string", "name": "label"}], "type": "record", "name": "Foo"}}, "name": "mapField"}, {"type": ["boolean", "double", {"items": "bytes", "type": "array"}], "name": "unionField"}, {"type": {"symbols": ["A", "B", "C"], "type": "enum", "name": "Kind"}, "name": "enumField"}, {"type": {"type": "fixed", "name": "MD5", "size": 16}, "name": "fixedField"}, {"type": {"fields": [{"type": "string", "name": "label"}, {"type": {"items": "org.apache.avro.Node", "type": "array"}, "name": "children"}], "type": "record", "name": "Node"}, "name": "recordField"}]}
+',
+ true,
+ '{"type":"record","name":"Interop","namespace":"org.apache.avro","fields":[{"name":"intField","type":"int"},{"name":"longField","type":"long"},{"name":"stringField","type":"string"},{"name":"boolField","type":"boolean"},{"name":"floatField","type":"float"},{"name":"doubleField","type":"double"},{"name":"bytesField","type":"bytes"},{"name":"nullField","type":"null"},{"name":"arrayField","type":{"type":"array","items":"double"}},{"name":"mapField","type":{"type":"map","values":{"type":"record","name":"Foo","fields":[{"name":"label","type":"string"}]}}},{"name":"unionField","type":["boolean","double",{"type":"array","items":"bytes"}]},{"name":"enumField","type":{"type":"enum","name":"Kind","symbols":["A","B","C"]}},{"name":"fixedField","type":{"type":"fixed","name":"MD5","size":16}},{"name":"recordField","type":{"type":"record","name":"Node","fields":[{"name":"label","type":"string"},{"name":"children","type":{"type":"array","items":"Node"}}]}}]}'
+ );
+ $record_examples[] = new SchemaExample(
+ '
{"type": "record",
"name": "ipAddr",
"fields": [{"name": "addr",
"type": [{"name": "IPv6", "type": "fixed", "size": 16},
{"name": "IPv4", "type": "fixed", "size": 4}]}]}
- ', true,
- '{"type":"record","name":"ipAddr","fields":[{"name":"addr","type":[{"type":"fixed","name":"IPv6","size":16},{"type":"fixed","name":"IPv4","size":4}]}]}');
- $record_examples [] = new SchemaExample('
+ ',
+ true,
+ '{"type":"record","name":"ipAddr","fields":[{"name":"addr","type":[{"type":"fixed","name":"IPv6","size":16},{"type":"fixed","name":"IPv4","size":4}]}]}'
+ );
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Address",
"fields": [{"type": "string"},
{"type": "string", "name": "City"}]}
', false);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"name": "Event",
"fields": [{"name": "Sponsor"},
{"name": "City", "type": "string"}]}
', false);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"type": "record",
"fields": "His vision, from the constantly passing bars,"
"name", "Rainer"}
', false);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample('
{"name": ["Tom", "Jerry"],
"type": "record",
"fields": [{"name": "name", "type": "string"}]}
', false);
- $record_examples [] = new SchemaExample('
+ $record_examples[] = new SchemaExample(
+ '
{"type":"record","name":"foo","doc":"doc string",
"fields":[{"name":"bar", "type":"int", "order":"ascending", "default":1}]}
',
true,
- '{"type":"record","name":"foo","doc":"doc string","fields":[{"name":"bar","type":"int","default":1,"order":"ascending"}]}');
- $record_examples [] = new SchemaExample('
+ '{"type":"record","name":"foo","doc":"doc string","fields":[{"name":"bar","type":"int","default":1,"order":"ascending"}]}'
+ );
+ $record_examples[] = new SchemaExample('
{"type":"record", "name":"foo", "doc":"doc string",
"fields":[{"name":"bar", "type":"int", "order":"bad"}]}
', false);
$record_examples[] = new SchemaExample(
- '{"type":"record", "name":"Record2", "aliases":["Record1"]}', false);
+ '{"type":"record", "name":"Record2", "aliases":["Record1"]}',
+ false
+ );
- self::$examples = array_merge($primitive_examples,
+ self::$examples = array_merge(
+ $primitive_examples,
$fixed_examples,
$enum_examples,
$array_examples,
$map_examples,
$union_examples,
- $record_examples);
- self::$valid_examples = array();
+ $record_examples
+ );
+ self::$valid_examples = [];
foreach (self::$examples as $example) {
if ($example->is_valid) {
- self::$valid_examples [] = $example;
+ self::$valid_examples[] = $example;
}
}
}
@@ -450,299 +787,19 @@ protected static function make_primitive_examples()
{
$examples = [];
foreach ([
- 'null',
- 'boolean',
- 'int',
- 'long',
- 'float',
- 'double',
- 'bytes',
- 'string'
- ]
- as $type) {
- $examples [] = new SchemaExample(sprintf('"%s"', $type), true);
- $examples [] = new SchemaExample(sprintf('{"type": "%s"}', $type), true, sprintf('"%s"', $type));
- }
- return $examples;
- }
-
- /**
- * @dataProvider schema_examples_provider
- */
- function test_parse($example): void
- {
- $schema_string = $example->schema_string;
- try {
- $normalized_schema_string = $example->normalized_schema_string;
- $schema = AvroSchema::parse($schema_string);
- $this->assertTrue($example->is_valid,
- sprintf("schema_string: %s\n",
- $schema_string));
- $this->assertEquals($normalized_schema_string, (string) $schema);
- } catch (AvroSchemaParseException $e) {
- $this->assertFalse($example->is_valid,
- sprintf("schema_string: %s\n%s",
- $schema_string,
- $e->getMessage()));
- }
- }
-
- public function testToAvroIncludesAliases(): void
- {
- $hash = <<assertEquals($schema->toAvro(), json_decode($hash, true));
- }
-
- public function testValidateFieldAliases()
- {
- $this->expectException(AvroSchemaParseException::class);
- $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
- AvroSchema::parse(<<expectException(AvroSchemaParseException::class);
- $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
- AvroSchema::parse(<<expectException(AvroSchemaParseException::class);
- $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
- AvroSchema::parse(<<expectException(AvroSchemaParseException::class);
- $this->expectExceptionMessage('Invalid aliases value. Must be an array of strings.');
- AvroSchema::parse(<<expectException(AvroSchemaParseException::class);
- $this->expectExceptionMessage('Alias already in use');
- AvroSchema::parse(<<expectNotToPerformAssertions();
- AvroSchema::parse(<<toAvro(), json_decode($avro, true));
- }
-
- public static function invalidDecimalLogicalTypeDataProvider(): array
- {
- return [
- 'bytes - invalid precision' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": -1, "scale": 2}',
- new AvroException("Precision '-1' is invalid. It must be a positive integer."),
- ],
- 'bytes - invalid value for precision (float)' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": 11.23, "scale": 2}',
- new AvroException("Invalid value '11.23' for 'precision' attribute of decimal logical type."),
- ],
- 'bytes - invalid value for precision (string)' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": "banana", "scale": 2}',
- new AvroException("Invalid value 'banana' for 'precision' attribute of decimal logical type."),
- ],
- 'bytes - invalid scale' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": -1}',
- new AvroException("Scale '-1' is invalid. It must be a non-negative integer."),
- ],
- 'bytes - invalid scale for precision' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": 2}',
- new AvroException("Scale must be a lower than precision (scale='2', precision='2')."),
- ],
- 'bytes - invalid value for scale (float)' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": 9.12}',
- new AvroException("Invalid value '9.12' for 'scale' attribute of decimal logical type."),
- ],
- 'bytes - invalid value for scale (string)' => [
- '{"type": "bytes", "logicalType": "decimal", "precision": 2, "scale": "two"}',
- new AvroException("Invalid value 'two' for 'scale' attribute of decimal logical type."),
- ],
- 'fixed - invalid precision' => [
- '{"name": "fixed_decimal", "type": "fixed", "logicalType": "decimal", "size": 2, "precision": -1, "scale": 2}',
- new AvroException("Precision '-1' is invalid. It must be a positive integer."),
- ],
- 'fixed - invalid value for precision with specified size' => [
- '{"name": "fixed_decimal", "type": "fixed", "logicalType": "decimal", "size": 2, "precision": 6, "scale": 2}',
- new AvroException("Invalid precision for specified fixed size (size='2', precision='6')."),
- ],
- ];
- }
- /**
- * @dataProvider invalidDecimalLogicalTypeDataProvider
- */
- public function testDecimalLogicalTypeWithInvalidParameters(string $schema, AvroException $exception): void
- {
- $this->expectException(get_class($exception));
- $this->expectExceptionMessage($exception->getMessage());
- AvroSchema::parse($schema);
+ return $examples;
}
}
diff --git a/lang/php/test/StringIOTest.php b/lang/php/test/StringIOTest.php
index 096ff30c131..fcfa44104cc 100644
--- a/lang/php/test/StringIOTest.php
+++ b/lang/php/test/StringIOTest.php
@@ -1,4 +1,5 @@
assertEquals(0, $strio->tell());
@@ -41,7 +42,7 @@ public function test_write()
$this->assertEquals($strlen, $strio->tell());
}
- public function test_seek()
+ public function test_seek(): void
{
$strio = new AvroStringIO('abcdefghijklmnopqrstuvwxyz');
$strio->seek(4, AvroIO::SEEK_SET);
@@ -52,7 +53,7 @@ public function test_seek()
$this->assertEquals('wxyz', $strio->read(4));
}
- public function test_tell()
+ public function test_tell(): void
{
$strio = new AvroStringIO('foobar');
$this->assertEquals(0, $strio->tell());
@@ -61,7 +62,7 @@ public function test_tell()
$this->assertEquals($strlen, $strio->tell());
}
- public function test_read()
+ public function test_read(): void
{
$str = 'foobar';
$strio = new AvroStringIO($str);
@@ -69,7 +70,7 @@ public function test_read()
$this->assertEquals(substr($str, 0, $strlen), $strio->read($strlen));
}
- public function test_string_rep()
+ public function test_string_rep(): void
{
$writers_schema_json = '"null"';
$writers_schema = AvroSchema::parse($writers_schema_json);
@@ -79,8 +80,11 @@ public function test_string_rep()
$dw = new AvroDataIOWriter($strio, $datum_writer, $writers_schema_json);
$dw->close();
- $this->assertEquals(57, strlen($strio->string()),
- AvroDebug::asciiString($strio->string()));
+ $this->assertEquals(
+ 57,
+ strlen((string) $strio->string()),
+ AvroDebug::asciiString($strio->string())
+ );
$read_strio = new AvroStringIO($strio->string());
diff --git a/lang/php/test/generate_interop_data.php b/lang/php/test/generate_interop_data.php
index fc9da0575bb..503489de2b6 100644
--- a/lang/php/test/generate_interop_data.php
+++ b/lang/php/test/generate_interop_data.php
@@ -1,5 +1,6 @@
#!/usr/bin/env php
[5.0, -6.0, -10.5],
'mapField' => [
'a' => ['label' => 'a'],
- 'c' => ['label' => '3P0']
+ 'c' => ['label' => '3P0'],
],
'unionField' => 14.5,
'enumField' => 'C',
@@ -44,15 +45,15 @@
'children' => [
[
'label' => 'inner',
- 'children' => []
- ]
- ]
- ]
+ 'children' => [],
+ ],
+ ],
+ ],
];
$schema_json = file_get_contents(AVRO_INTEROP_SCHEMA);
foreach (AvroDataIO::validCodecs() as $codec) {
- $file_name = $codec == AvroDataIO::NULL_CODEC ? 'php.avro' : sprintf('php_%s.avro', $codec);
+ $file_name = AvroDataIO::NULL_CODEC == $codec ? 'php.avro' : sprintf('php_%s.avro', $codec);
$data_file = implode(DIRECTORY_SEPARATOR, [AVRO_BUILD_DATA_DIR, $file_name]);
$io_writer = AvroDataIO::openFile($data_file, 'w', $schema_json, $codec);
$io_writer->append($datum);
diff --git a/lang/php/test/test_helper.php b/lang/php/test/test_helper.php
index 78af6775aca..0f938a16763 100644
--- a/lang/php/test/test_helper.php
+++ b/lang/php/test/test_helper.php
@@ -1,4 +1,5 @@