diff --git a/.php_cs b/.php_cs
index 8c61b21..f094404 100644
--- a/.php_cs
+++ b/.php_cs
@@ -8,46 +8,51 @@ return \PhpCsFixer\Config::create()
->setRules([
'@PSR2' => true,
- 'array_syntax' => [
- 'syntax' => 'short'
- ],
- 'binary_operator_spaces' => [
- 'align_double_arrow' => null,
- 'align_equals' => false,
- ],
+ 'align_multiline_comment' => true,
+ 'array_indentation' => true,
+ 'array_syntax' => ['syntax' => 'short'],
+ 'backtick_to_shell_exec' => true,
+ 'binary_operator_spaces' => true,
'blank_line_after_opening_tag' => true,
'cast_spaces' => true,
+ 'class_attributes_separation' => ['elements' => ['method']],
+ 'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
- 'concat_space' => [
- 'spacing' => 'one'
- ],
+ 'concat_space' => ['spacing' => 'one'],
'declare_equal_normalize' => true,
'dir_constant' => true,
'ereg_to_preg' => true,
+ 'fully_qualified_strict_types' => true,
'function_to_constant' => true,
'function_typehint_space' => true,
- 'hash_to_slash_comment' => true,
'heredoc_to_nowdoc' => true,
'include' => true,
'is_null' => true,
+ 'list_syntax' => ['syntax' => 'short'],
+ 'logical_operators' => true,
'lowercase_cast' => true,
+ 'lowercase_static_reference' => true,
'magic_constant_casing' => true,
- 'method_separation' => true,
'modernize_types_casting' => true,
+ 'multiline_comment_opening_closing' => true,
+ 'multiline_whitespace_before_semicolons' => true,
+ 'native_constant_invocation' => true,
'native_function_casing' => true,
+ 'native_function_invocation' => ['include' => ['@compiler_optimized']],
'new_with_braces' => true,
'no_alias_functions' => true,
+ 'no_binary_string' => true,
'no_blank_lines_after_class_opening' => true,
'no_blank_lines_after_phpdoc' => true,
'no_empty_comment' => true,
'no_empty_phpdoc' => true,
'no_empty_statement' => true,
- 'no_extra_consecutive_blank_lines' => true,
+ 'no_extra_blank_lines' => true,
+ 'no_homoglyph_names' => true,
'no_leading_import_slash' => true,
'no_leading_namespace_whitespace' => true,
'no_mixed_echo_print' => true,
'no_multiline_whitespace_around_double_arrow' => true,
- 'no_multiline_whitespace_before_semicolons' => true,
'no_php4_constructor' => true,
'no_short_bool_cast' => true,
'no_singleline_whitespace_before_semicolons' => true,
@@ -55,6 +60,9 @@ return \PhpCsFixer\Config::create()
'no_trailing_comma_in_list_call' => true,
'no_trailing_comma_in_singleline_array' => true,
'no_unneeded_control_parentheses' => true,
+ 'no_unneeded_curly_braces' => true,
+ 'no_unneeded_final_method' => true,
+ 'no_unreachable_default_argument_value' => true,
'no_unused_imports' => true,
'no_useless_return' => true,
'no_whitespace_before_comma_in_array' => true,
@@ -62,38 +70,53 @@ return \PhpCsFixer\Config::create()
'non_printable_character' => true,
'normalize_index_brace' => true,
'object_operator_without_whitespace' => true,
- 'ordered_class_elements' => [
- 'order' => ['use_trait', 'constant', 'property', 'construct', 'method'],
- ],
+ 'ordered_class_elements' => ['order' => ['use_trait', 'constant', 'property', 'construct', 'method']],
'ordered_imports' => true,
'php_unit_construct' => true,
- 'php_unit_dedicate_assert' => true,
+ 'php_unit_dedicate_assert' => ['target' => 'newest'],
+ 'php_unit_expectation' => true,
+ 'php_unit_mock' => true,
+ 'php_unit_namespaced' => true,
+ 'php_unit_no_expectation_annotation' => true,
+ 'php_unit_set_up_tear_down_visibility' => true,
'php_unit_strict' => true,
+ 'php_unit_test_case_static_method_calls' => ['call_type' => 'this'],
'phpdoc_add_missing_param_annotation' => true,
+ 'phpdoc_align' => ['align' => 'left'],
'phpdoc_annotation_without_dot' => true,
'phpdoc_indent' => true,
'phpdoc_inline_tag' => true,
'phpdoc_no_access' => true,
'phpdoc_no_alias_tag' => true,
'phpdoc_no_package' => true,
+ 'phpdoc_no_useless_inheritdoc' => true,
+ 'phpdoc_return_self_reference' => true,
'phpdoc_scalar' => true,
'phpdoc_single_line_var_spacing' => true,
'phpdoc_summary' => true,
+ 'phpdoc_to_comment' => true,
'phpdoc_trim' => true,
+ 'phpdoc_trim_consecutive_blank_line_separation' => true,
'phpdoc_types' => true,
'phpdoc_var_without_name' => true,
'pow_to_exponentiation' => true,
'psr4' => true,
'return_type_declaration' => true,
'self_accessor' => true,
+ 'semicolon_after_instruction' => true,
+ 'set_type_to_cast' => true,
'short_scalar_cast' => true,
+ 'simplified_null_return' => true,
'single_blank_line_before_namespace' => true,
+ 'single_line_comment_style' => true,
'single_quote' => true,
'space_after_semicolon' => true,
+ 'standardize_increment' => true,
'standardize_not_equals' => true,
'strict_comparison' => true,
'strict_param' => true,
'ternary_operator_spaces' => true,
+ 'ternary_to_null_coalescing' => true,
'trailing_comma_in_multiline_array' => true,
'trim_array_spaces' => true,
'whitespace_after_comma_in_array' => true,
diff --git a/.travis.yml b/.travis.yml
index 599b28f..fbb0919 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,31 +1,33 @@
language: php
sudo: false
-dist: trusty
php:
- 5.6
- 7.0
- 7.1
- - hhvm
+ - 7.2
cache:
directories:
- - vendor
+ - build/.composer-cache
before_install:
+ - export COMPOSER_CACHE_DIR="$(pwd)/build/.composer-cache"
- export XDEBUG="/home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini"
- - is_hhvm () { [[ $TRAVIS_PHP_VERSION =~ ^hhvm ]]; }
- - is_hhvm || mv -v "$XDEBUG" "$XDEBUG.disabled"
+ - mv -v "$XDEBUG" "$XDEBUG.disabled"
install:
- - travis_retry composer update -a --no-interaction
- - travis_retry wget https://scrutinizer-ci.com/ocular.phar
+ - mkdir -p build/php_codesniffer build/php-cs-fixer build/ocular
+ - composer require --no-suggest --no-progress -n -a -d build/php-cs-fixer "friendsofphp/php-cs-fixer:^2.12"
+ - composer require --no-suggest --no-progress -n -a -d build/php_codesniffer "squizlabs/php_codesniffer:^3.3"
+ - composer require --no-suggest --no-progress -n -a -d build/ocular "scrutinizer/ocular:^1.5"
+ - composer update --no-suggest --no-progress -n -a
script:
- - vendor/bin/phpcs --standard=PSR2 src tests
- - vendor/bin/php-cs-fixer fix -v --dry-run --allow-risky=yes --using-cache=no
- - if is_hhvm; then echo "xdebug.enable = On" >> /etc/hhvm/php.ini; else mv -v "$XDEBUG.disabled" "$XDEBUG"; fi
- - vendor/bin/phpunit --coverage-clover=coverage.clover --coverage-text
+ - build/php_codesniffer/vendor/bin/phpcs -p --standard=PSR2 src tests
+ - build/php-cs-fixer/vendor/bin/php-cs-fixer fix -v --dry-run --allow-risky=yes --using-cache=no
+ - mv -v "$XDEBUG.disabled" "$XDEBUG"
+ - vendor/bin/phpunit --coverage-clover=build/coverage.clover --coverage-text
after_script:
- - is_hhvm || php ocular.phar code-coverage:upload --format=php-clover coverage.clover
+ - build/ocular/vendor/bin/ocular code-coverage:upload --format=php-clover build/coverage.clover
diff --git a/CHANGES.md b/CHANGES.md
index 344c06a..d1e51c3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,15 @@
# Changelog #
+## v2.4.0 (2018-07-03) ##
+
+ * Added `string.classes` option, which allows to define an array of classes or
+ namespaces to encode using the `::class` format, when encountered as strings
+ * Added `string.imports` options, which allows to define the used imports to write
+ the `::class` format strings using shorter imported notation
+ * Support for HHVM has been dropped, as HHVM no longer aims for PHP compatibility
+ * Added travis builds for PHP 7.2
+ * Change some rules in the used coding standard
+
## v2.3.0 (2017-07-15) ##
* Added `string.utf8` option which causes the string encoder to escape all
diff --git a/LICENSE b/LICENSE
index 7f2594c..74ef170 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2013-2017 Riikka Kalliomäki
+Copyright (c) 2013-2018 Riikka Kalliomäki
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index 385b8a5..f890a62 100644
--- a/README.md
+++ b/README.md
@@ -201,6 +201,23 @@ apply to following calls.
multibyte UTF-8 characters in strings are encoded using the PHP7 unicode
code point syntax. Note that this syntax does not work in PHP versions
earlier than 7.0.
+
+ * **string.classes** : <string[]> ([])
+ Defines a list of classes or class namespace prefixes for classes that
+ can be encoded using the class resolution operator `::class` when
+ encountered in strings. e.g. providing the value `['Riimu\\']` would encode
+ all strings that look like class names in the `Riimu` namespace like
+ `Riimu\Kit\PHPEncoder::class`.
+
+ * **string.imports** : <string[]> ([])
+ List of imports used in the resulting code file, which allows class names
+ to be written using shorter format. The list should be an associative array
+ with the namespace or class as the key and the used name as the value. Use
+ empty string to indicate the current namespace.
+
+ For example, if the resulting file would have `namespace Riimu\Kit\PHPEncoder;`
+ and `use PHPUnit\Framework\TestCase;`, you could set up the array as
+ `['Riimu\\Kit\\PHPEncoder\\' => '', 'PHPUnit\\Framework\\TestCase' => 'TestCase']`
* **array.short** : <boolean> (true)
When set to `true`, arrays are enclosed using square brackets `[]` instead
@@ -279,6 +296,6 @@ on HHVM.
## Credits ##
-This library is Copyright (c) 2013-2017 Riikka Kalliomäki.
+This library is Copyright (c) 2013-2018 Riikka Kalliomäki.
See LICENSE for license and copying information.
diff --git a/composer.json b/composer.json
index 03ce079..cacc5ce 100644
--- a/composer.json
+++ b/composer.json
@@ -22,9 +22,7 @@
"php": ">=5.6.0"
},
"require-dev": {
- "phpunit/phpunit": "^5.7 || ^6.2",
- "squizlabs/php_codesniffer": "^3.0",
- "friendsofphp/php-cs-fixer": "^2.3"
+ "phpunit/phpunit": "^7.2 || ^6.5 || ^5.7"
},
"suggest": {
"ext-gmp": "To convert GMP numbers into PHP code"
diff --git a/examples/class_resolution.php b/examples/class_resolution.php
new file mode 100644
index 0000000..3cf0967
--- /dev/null
+++ b/examples/class_resolution.php
@@ -0,0 +1,37 @@
+ [
+ 'Riimu\\',
+ 'PHPUnit\\Framework\\TestCase',
+ 'DateTime',
+ ],
+ 'string.imports' => [
+ 'Riimu\\Kit\\PHPEncoder\\' => '',
+ 'PHPUnit\\Framework\\TestCase' => 'TestCase',
+ ],
+]);
+
+
+echo "encode([
+ \PHPUnit\Framework\TestCase::class,
+ \Riimu\Kit\PHPEncoder\PHPEncoder::class,
+ \Riimu\Kit\PHPEncoder\Encoder\Encoder::class,
+ \DateTime::class,
+ \DateTimeInterface::class, // Will be encoded as plain string, since it's not allowed by string.classes
+]);
+
+echo ");\n";
diff --git a/src/Encoder/ArrayEncoder.php b/src/Encoder/ArrayEncoder.php
index 2597b2c..e516fe3 100644
--- a/src/Encoder/ArrayEncoder.php
+++ b/src/Encoder/ArrayEncoder.php
@@ -5,20 +5,20 @@
/**
* Encoder for array values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class ArrayEncoder implements Encoder
{
/** @var array Default values for options in the encoder */
private static $defaultOptions = [
- 'array.short' => true,
- 'array.base' => 0,
+ 'array.short' => true,
+ 'array.base' => 0,
'array.indent' => 4,
- 'array.align' => false,
+ 'array.align' => false,
'array.inline' => 70,
- 'array.omit' => true,
- 'array.eol' => false,
+ 'array.omit' => true,
+ 'array.eol' => false,
];
public function getDefaultOptions()
@@ -28,7 +28,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_array($value);
+ return \is_array($value);
}
public function encode($value, $depth, array $options, callable $encode)
@@ -107,7 +107,7 @@ private function getInlineArray(array $lines, array $options)
if (preg_match('/[\r\n\t]/', $output)) {
return false;
- } elseif ($options['array.inline'] === true || strlen($output) <= (int) $options['array.inline']) {
+ } elseif ($options['array.inline'] === true || \strlen($output) <= (int) $options['array.inline']) {
return $output;
}
@@ -125,7 +125,7 @@ private function buildArray(array $lines, $depth, array $options)
{
$indent = $this->buildIndent($options['array.base'], $options['array.indent'], $depth + 1);
$last = $this->buildIndent($options['array.base'], $options['array.indent'], $depth);
- $eol = $options['array.eol'] === false ? PHP_EOL : (string) $options['array.eol'];
+ $eol = $options['array.eol'] === false ? \PHP_EOL : (string) $options['array.eol'];
return $this->wrap(
sprintf('%s%s%s,%1$s%s', $eol, $indent, implode(',' . $eol . $indent, $lines), $last),
@@ -153,10 +153,10 @@ private function wrap($string, $short)
*/
private function buildIndent($base, $indent, $depth)
{
- $base = is_int($base) ? str_repeat(' ', $base) : (string) $base;
+ $base = \is_int($base) ? str_repeat(' ', $base) : (string) $base;
return $depth === 0 ? $base : $base . str_repeat(
- is_int($indent) ? str_repeat(' ', $indent) : (string) $indent,
+ \is_int($indent) ? str_repeat(' ', $indent) : (string) $indent,
$depth
);
}
@@ -180,7 +180,7 @@ private function getAlignedPairs(array $array, callable $encode)
$format = sprintf('%%-%ds => %%s', max(array_map('strlen', $keys)));
$pairs = [];
- for ($i = 0, $count = count($keys); $i < $count; $i++) {
+ for ($i = 0, $count = \count($keys); $i < $count; $i++) {
$pairs[] = sprintf($format, $keys[$i], $values[$i]);
}
@@ -225,7 +225,7 @@ private function canOmitKey($key, & $nextIndex)
{
$result = $key === $nextIndex;
- if (is_int($key)) {
+ if (\is_int($key)) {
$nextIndex = max($key + 1, $nextIndex);
}
diff --git a/src/Encoder/BooleanEncoder.php b/src/Encoder/BooleanEncoder.php
index 0797818..3f8350d 100644
--- a/src/Encoder/BooleanEncoder.php
+++ b/src/Encoder/BooleanEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for boolean values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class BooleanEncoder implements Encoder
@@ -22,7 +22,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_bool($value);
+ return \is_bool($value);
}
public function encode($value, $depth, array $options, callable $encode)
diff --git a/src/Encoder/Encoder.php b/src/Encoder/Encoder.php
index 0456bd1..fcbdd56 100644
--- a/src/Encoder/Encoder.php
+++ b/src/Encoder/Encoder.php
@@ -5,7 +5,7 @@
/**
* Interface for different types of value encoders.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
interface Encoder
diff --git a/src/Encoder/FloatEncoder.php b/src/Encoder/FloatEncoder.php
index 2ca1ebf..9a8094a 100644
--- a/src/Encoder/FloatEncoder.php
+++ b/src/Encoder/FloatEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for float values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class FloatEncoder implements Encoder
@@ -15,7 +15,7 @@ class FloatEncoder implements Encoder
/** @var array Default values for options in the encoder */
private static $defaultOptions = [
- 'float.integers' => false,
+ 'float.integers' => false,
'float.precision' => 17,
'float.export' => false,
];
@@ -27,7 +27,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_float($value);
+ return \is_float($value);
}
public function encode($value, $depth, array $options, callable $encode)
@@ -86,9 +86,9 @@ private function isInteger($float, $allowIntegers)
*/
private function encodeInteger($float, callable $encode)
{
- $minimum = defined('PHP_INT_MIN') ? PHP_INT_MIN : ~PHP_INT_MAX;
+ $minimum = \defined('PHP_INT_MIN') ? \PHP_INT_MIN : ~\PHP_INT_MAX;
- if ($float >= $minimum && $float <= PHP_INT_MAX) {
+ if ($float >= $minimum && $float <= \PHP_INT_MAX) {
return $encode((int) $float);
}
@@ -105,7 +105,7 @@ private function determinePrecision($options)
$precision = $options['float.precision'];
if ($precision === false) {
- $precision = defined('HHVM_VERSION') ? 17 : ini_get('serialize_precision');
+ $precision = ini_get('serialize_precision');
}
return max(1, (int) $precision);
diff --git a/src/Encoder/GMPEncoder.php b/src/Encoder/GMPEncoder.php
index 777004e..7386ec1 100644
--- a/src/Encoder/GMPEncoder.php
+++ b/src/Encoder/GMPEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for GMP number types.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class GMPEncoder implements Encoder
@@ -17,7 +17,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_object($value) && get_class($value) === \GMP::class;
+ return \is_object($value) && \get_class($value) === \GMP::class;
}
public function encode($value, $depth, array $options, callable $encode)
diff --git a/src/Encoder/IntegerEncoder.php b/src/Encoder/IntegerEncoder.php
index 1ef6a5f..33eec60 100644
--- a/src/Encoder/IntegerEncoder.php
+++ b/src/Encoder/IntegerEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for integer values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class IntegerEncoder implements Encoder
@@ -46,7 +46,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_int($value);
+ return \is_int($value);
}
public function encode($value, $depth, array $options, callable $encode)
@@ -88,7 +88,7 @@ public function encodeOctal($integer)
*/
public function encodeDecimal($integer, $options)
{
- if ($integer === 1 << (PHP_INT_SIZE * 8 - 1)) {
+ if ($integer === 1 << (\PHP_INT_SIZE * 8 - 1)) {
return sprintf('(int)%s%d', $options['whitespace'] ? ' ' : '', $integer);
}
diff --git a/src/Encoder/NullEncoder.php b/src/Encoder/NullEncoder.php
index ca6201d..1fd8672 100644
--- a/src/Encoder/NullEncoder.php
+++ b/src/Encoder/NullEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for null values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class NullEncoder implements Encoder
diff --git a/src/Encoder/ObjectEncoder.php b/src/Encoder/ObjectEncoder.php
index dac1901..bdbfa5b 100644
--- a/src/Encoder/ObjectEncoder.php
+++ b/src/Encoder/ObjectEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for generic objects.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class ObjectEncoder implements Encoder
@@ -14,7 +14,7 @@ class ObjectEncoder implements Encoder
private static $defaultOptions = [
'object.method' => true,
'object.format' => 'vars',
- 'object.cast' => true,
+ 'object.cast' => true,
];
public function getDefaultOptions()
@@ -24,7 +24,7 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_object($value);
+ return \is_object($value);
}
public function encode($value, $depth, array $options, callable $encode)
@@ -54,7 +54,7 @@ private function encodeObject($object, array $options, callable $encode)
} elseif ($options['object.format'] === 'serialize') {
return sprintf('unserialize(%s)', $encode(serialize($object)));
} elseif ($options['object.format'] === 'export') {
- return sprintf('\\%s::__set_state(%s)', get_class($object), $encode($this->getObjectState($object)));
+ return sprintf('\\%s::__set_state(%s)', \get_class($object), $encode($this->getObjectState($object)));
}
return $this->encodeObjectArray($object, $options, $encode);
@@ -70,7 +70,7 @@ private function encodeObject($object, array $options, callable $encode)
*/
private function encodeObjectArray($object, array $options, callable $encode)
{
- if (!in_array((string) $options['object.format'], ['array', 'vars', 'iterate'], true)) {
+ if (!\in_array((string) $options['object.format'], ['array', 'vars', 'iterate'], true)) {
throw new \RuntimeException('Invalid object encoding format: ' . $options['object.format']);
}
diff --git a/src/Encoder/StringEncoder.php b/src/Encoder/StringEncoder.php
index bc077ae..1fdcb78 100644
--- a/src/Encoder/StringEncoder.php
+++ b/src/Encoder/StringEncoder.php
@@ -5,7 +5,7 @@
/**
* Encoder for string values.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class StringEncoder implements Encoder
@@ -15,6 +15,8 @@ class StringEncoder implements Encoder
'string.escape' => true,
'string.binary' => false,
'string.utf8' => false,
+ 'string.classes' => [],
+ 'string.imports' => [],
];
public function getDefaultOptions()
@@ -24,21 +26,90 @@ public function getDefaultOptions()
public function supports($value)
{
- return is_string($value);
+ return \is_string($value);
}
public function encode($value, $depth, array $options, callable $encode)
{
$value = (string) $value;
+ if ($this->isClassName($value, $options)) {
+ return $this->getClassName($value, $options);
+ }
+
if (preg_match('/[^\x20-\x7E]/', $value)) {
- if ($this->isBinaryString($value, $options)) {
- return $this->encodeBinaryString($value);
- } elseif ($options['string.escape']) {
- return $this->getDoubleQuotedString($value, $options);
+ return $this->getComplexString($value, $options);
+ }
+
+ return $this->getSingleQuotedString($value);
+ }
+
+ /**
+ * Tests if the given value is a string that could be encoded as a class name constant.
+ * @param string $value The string to test
+ * @param array $options The string encoding options
+ * @return bool True if string can be encoded as class constant, false if not
+ */
+ private function isClassName($value, array $options)
+ {
+ if (preg_match('/^([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\\\\(?1))*$/', $value) !== 1) {
+ return false;
+ }
+
+ return array_intersect(iterator_to_array($this->iterateNamespaces($value)), $options['string.classes']) !== [];
+ }
+
+ /**
+ * Encodes the given string as a class name constant based on used imports.
+ * @param string $value The string to encode
+ * @param array $options The string encoding options
+ * @return string The class constant PHP code representation
+ */
+ private function getClassName($value, array $options)
+ {
+ foreach ($this->iterateNamespaces($value) as $partial) {
+ if (isset($options['string.imports'][$partial])) {
+ $trimmed = substr($value, \strlen(rtrim($partial, '\\')));
+ return ltrim(sprintf('%s%s::class', rtrim($options['string.imports'][$partial], '\\'), $trimmed), '\\');
}
}
+ return sprintf('\\%s::class', $value);
+ }
+
+ /**
+ * Iterates over the variations of the namespace for the given class name.
+ * @param string $value The class name to iterate over
+ * @return \Generator|string[] The namespace parts of the string
+ */
+ private function iterateNamespaces($value)
+ {
+ yield $value;
+
+ $parts = explode('\\', '\\' . $value);
+ $count = \count($parts);
+
+ for ($i = 1; $i < $count; $i++) {
+ yield ltrim(implode('\\', \array_slice($parts, 0, -$i)), '\\') . '\\';
+ }
+ }
+
+ /**
+ * Returns the PHP code representation for the string that is not just simple ascii characters.
+ * @param string $value The string to encode
+ * @param array $options The string encoding options
+ * @return string The PHP code representation for the complex string
+ */
+ private function getComplexString($value, array $options)
+ {
+ if ($this->isBinaryString($value, $options)) {
+ return $this->encodeBinaryString($value);
+ }
+
+ if ($options['string.escape']) {
+ return $this->getDoubleQuotedString($value, $options);
+ }
+
return $this->getSingleQuotedString($value);
}
@@ -102,8 +173,8 @@ private function getDoubleQuotedString($string, $options)
"\n" => '\n',
"\r" => '\r',
"\t" => '\t',
- '$' => '\$',
- '"' => '\"',
+ '$' => '\$',
+ '"' => '\"',
'\\' => '\\\\',
]);
@@ -112,7 +183,7 @@ private function getDoubleQuotedString($string, $options)
}
$hexFormat = function ($matches) use ($options) {
- return sprintf($options['hex.capitalize'] ? '\x%02X' : '\x%02x', ord($matches[0]));
+ return sprintf($options['hex.capitalize'] ? '\x%02X' : '\x%02x', \ord($matches[0]));
};
return sprintf('"%s"', preg_replace_callback('/[^\x20-\x7E]/', $hexFormat, $string));
@@ -147,20 +218,20 @@ private function encodeUtf8($string, $options)
*/
private function getCodePoint($bytes)
{
- if (strlen($bytes) === 2) {
- return ((ord($bytes[0]) & 0b11111) << 6)
- | (ord($bytes[1]) & 0b111111);
+ if (\strlen($bytes) === 2) {
+ return ((\ord($bytes[0]) & 0b11111) << 6)
+ | (\ord($bytes[1]) & 0b111111);
}
- if (strlen($bytes) === 3) {
- return ((ord($bytes[0]) & 0b1111) << 12)
- | ((ord($bytes[1]) & 0b111111) << 6)
- | (ord($bytes[2]) & 0b111111);
+ if (\strlen($bytes) === 3) {
+ return ((\ord($bytes[0]) & 0b1111) << 12)
+ | ((\ord($bytes[1]) & 0b111111) << 6)
+ | (\ord($bytes[2]) & 0b111111);
}
- return ((ord($bytes[0]) & 0b111) << 18)
- | ((ord($bytes[1]) & 0b111111) << 12)
- | ((ord($bytes[2]) & 0b111111) << 6)
- | (ord($bytes[3]) & 0b111111);
+ return ((\ord($bytes[0]) & 0b111) << 18)
+ | ((\ord($bytes[1]) & 0b111111) << 12)
+ | ((\ord($bytes[2]) & 0b111111) << 6)
+ | (\ord($bytes[3]) & 0b111111);
}
}
diff --git a/src/InvalidOptionException.php b/src/InvalidOptionException.php
index 4243378..5a7ec97 100644
--- a/src/InvalidOptionException.php
+++ b/src/InvalidOptionException.php
@@ -5,7 +5,7 @@
/**
* Exception that gets thrown if invalid encoder options are used.
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2015-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2015-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class InvalidOptionException extends \InvalidArgumentException
diff --git a/src/PHPEncoder.php b/src/PHPEncoder.php
index 5d6bffb..412572f 100644
--- a/src/PHPEncoder.php
+++ b/src/PHPEncoder.php
@@ -11,7 +11,7 @@
* in specific way.
*
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class PHPEncoder
@@ -24,11 +24,11 @@ class PHPEncoder
/** @var array Default values for options in the encoder */
private static $defaultOptions = [
- 'whitespace' => true,
+ 'whitespace' => true,
'recursion.detect' => true,
'recursion.ignore' => false,
- 'recursion.max' => false,
- 'hex.capitalize' => false,
+ 'recursion.max' => false,
+ 'hex.capitalize' => false,
];
/**
@@ -230,6 +230,6 @@ private function encodeValue($value, $depth, array $options, callable $encode)
}
}
- throw new \InvalidArgumentException(sprintf("Unsupported value type '%s'", gettype($value)));
+ throw new \InvalidArgumentException(sprintf("Unsupported value type '%s'", \gettype($value)));
}
}
diff --git a/src/autoload.php b/src/autoload.php
index 45ca83e..7e3bbb9 100644
--- a/src/autoload.php
+++ b/src/autoload.php
@@ -4,8 +4,8 @@
// Bundled autoloader provided as an optional alternative to composer autoloader
spl_autoload_register(function ($class) {
- if (strncmp($class, __NAMESPACE__, strlen(__NAMESPACE__)) === 0) {
- $path = __DIR__ . strtr(substr($class, strlen(__NAMESPACE__)), ['\\' => DIRECTORY_SEPARATOR]) . '.php';
+ if (strncmp($class, __NAMESPACE__, \strlen(__NAMESPACE__)) === 0) {
+ $path = __DIR__ . strtr(substr($class, \strlen(__NAMESPACE__)), ['\\' => \DIRECTORY_SEPARATOR]) . '.php';
if (file_exists($path)) {
require $path;
diff --git a/tests/tests/ArrayEncodingTest.php b/tests/tests/ArrayEncodingTest.php
index b1c726f..3e45515 100644
--- a/tests/tests/ArrayEncodingTest.php
+++ b/tests/tests/ArrayEncodingTest.php
@@ -4,7 +4,7 @@
/**
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class ArrayEncodingTest extends EncodingTestCase
@@ -53,7 +53,7 @@ public function testInlineWithMultiLineString()
]
RESULT
),
- ['foo' . PHP_EOL . 'bar'],
+ ['foo' . \PHP_EOL . 'bar'],
['string.escape' => false]
);
}
@@ -147,7 +147,7 @@ public function testWhitespace()
"[\n1 => 1,\n0 => 0,\n]",
[1 => 1, 0 => 0],
[
- 'array.eol' => "\n",
+ 'array.eol' => "\n",
'array.indent' => 0,
]
);
@@ -156,7 +156,7 @@ public function testWhitespace()
"[\r1 => 1,\r0 => 0,\r]",
[1 => 1, 0 => 0],
[
- 'array.eol' => "\r",
+ 'array.eol' => "\r",
'array.indent' => 0,
]
);
@@ -172,7 +172,7 @@ public function testWhitespace()
),
['foo' => 'bar', 1 => true],
[
- 'array.base' => 1,
+ 'array.base' => 1,
'array.indent' => 2,
]
);
@@ -188,7 +188,7 @@ public function testWhitespace()
),
['foo' => 'bar', 1 => true],
[
- 'array.base' => "\t",
+ 'array.base' => "\t",
'array.indent' => "\t",
]
);
@@ -351,7 +351,7 @@ public function testInlineOnAlignedArray()
private function format($string, $eol = false)
{
if ($eol === false) {
- $eol = PHP_EOL;
+ $eol = \PHP_EOL;
}
return preg_replace('/\r\n|\r|\n/', $eol, $string);
diff --git a/tests/tests/EncodingTest.php b/tests/tests/EncodingTest.php
index 52b5778..fee5d9f 100644
--- a/tests/tests/EncodingTest.php
+++ b/tests/tests/EncodingTest.php
@@ -7,7 +7,7 @@
/**
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class EncodingTest extends EncodingTestCase
@@ -62,13 +62,13 @@ public function testIntegerEncoding()
public function testMaximumInteger()
{
- $this->assertEncode((string) PHP_INT_MAX, PHP_INT_MAX);
+ $this->assertEncode((string) \PHP_INT_MAX, \PHP_INT_MAX);
}
public function testMinimumInteger()
{
- $this->assertEncode('(int) ' . (-PHP_INT_MAX - 1), -PHP_INT_MAX - 1);
- $this->assertEncode('(int)' . (-PHP_INT_MAX - 1), -PHP_INT_MAX - 1, ['whitespace' => false]);
+ $this->assertEncode('(int) ' . (-\PHP_INT_MAX - 1), -\PHP_INT_MAX - 1);
+ $this->assertEncode('(int)' . (-\PHP_INT_MAX - 1), -\PHP_INT_MAX - 1, ['whitespace' => false]);
}
public function testIntegerTypes()
@@ -121,10 +121,6 @@ public function testFloatExponents()
public function testUsingIniPrecision()
{
- if (defined('HHVM_VERSION')) {
- $this->markTestSkipped();
- }
-
$float = 1.1234567890123456;
$serialize = ini_set('serialize_precision', 13);
@@ -135,13 +131,13 @@ public function testUsingIniPrecision()
public function testInfiniteFloat()
{
- $this->assertEncode('INF', INF);
- $this->assertEncode('-INF', -INF);
+ $this->assertEncode('INF', \INF);
+ $this->assertEncode('-INF', -\INF);
}
public function testNanFloat()
{
- $code = (new PHPEncoder())->encode(NAN);
+ $code = (new PHPEncoder())->encode(\NAN);
$this->assertSame('NAN', $code);
$value = eval("return $code;");
@@ -248,7 +244,7 @@ public function testUtf8String()
$this->assertEncode('"\nA"', "\nA", $encoder);
$this->assertSame('"\nA\u{c4}\x00"', $encoder->encode("\nAÄ\x00"));
- if (version_compare(PHP_VERSION, '7', '<')) {
+ if (version_compare(\PHP_VERSION, '7', '<')) {
$this->assertSame('"\u{a2}"', $encoder->encode("\xC2\xA2"));
$this->assertSame('"\u{20ac}"', $encoder->encode("\xE2\x82\xAC"));
$this->assertSame('"\u{10348}"', $encoder->encode("\xF0\x90\x8D\x88"));
@@ -264,9 +260,38 @@ public function testUtf8String()
$this->assertSame('"\nA\u{C4}\x00"', $encoder->encode("\nAÄ\x00"));
}
+ public function testClassStrings()
+ {
+ $encoder = new PHPEncoder(['string.classes' => [self::class]]);
+ $this->assertEncode('\\' . self::class . '::class', self::class, $encoder);
+ }
+
+ public function testImportedClassString()
+ {
+ $encoder = new PHPEncoder([
+ 'string.classes' => [\DateTime::class, PHPEncoder::class, FloatEncoder::class, Encoder::class],
+ 'string.imports' => ['\\' => '', __NAMESPACE__ . '\\' => 'Encoder', Encoder::class => 'EncoderInterface'],
+ ]);
+
+ $this->assertSame('DateTime::class', $encoder->encode(\DateTime::class));
+ $this->assertSame('Encoder\PHPEncoder::class', $encoder->encode(PHPEncoder::class));
+ $this->assertSame('Encoder\Encoder\FloatEncoder::class', $encoder->encode(FloatEncoder::class));
+ $this->assertSame('EncoderInterface::class', $encoder->encode(Encoder::class));
+ $this->assertSame("'DateTimeInterface'", $encoder->encode(\DateTimeInterface::class));
+
+ $encoder = new PHPEncoder([
+ 'string.classes' => [self::class],
+ 'string.imports' => [__NAMESPACE__ . '\\' => ''],
+ ]);
+
+ $code = sprintf('namespace ' . __NAMESPACE__ . '; return %s;', $encoder->encode(self::class));
+ $this->assertSame('namespace Riimu\Kit\PHPEncoder; return EncodingTest::class;', $code);
+ $this->assertSame(self::class, eval($code));
+ }
+
public function testGMPEncoding()
{
- if (!function_exists('gmp_init')) {
+ if (!\function_exists('gmp_init')) {
$this->markTestSkipped('Missing GMP library');
}
@@ -349,7 +374,7 @@ public function testMaxDeathOnNoRecursionDetection()
$encoder = new PHPEncoder([
'recursion.detect' => false,
- 'recursion.max' => 5,
+ 'recursion.max' => 5,
]);
$this->expectException(\RuntimeException::class);
diff --git a/tests/tests/EncodingTestCase.php b/tests/tests/EncodingTestCase.php
index ce5e0ba..b69a508 100644
--- a/tests/tests/EncodingTestCase.php
+++ b/tests/tests/EncodingTestCase.php
@@ -6,7 +6,7 @@
/**
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2015-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2015-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class EncodingTestCase extends TestCase
@@ -20,11 +20,11 @@ class EncodingTestCase extends TestCase
*/
protected function assertEncode($code, $value, $encoder = [], $initial = null)
{
- if (is_array($encoder)) {
+ if (\is_array($encoder)) {
$encoder = new PHPEncoder($encoder);
}
- $output = $encoder->encode(func_num_args() < 4 ? $value : $initial);
+ $output = $encoder->encode(\func_num_args() < 4 ? $value : $initial);
$this->assertSame($code, $output);
$this->assertSame($value, eval("return $output;"));
}
diff --git a/tests/tests/ObjectEncodingTest.php b/tests/tests/ObjectEncodingTest.php
index cb855b2..53758ff 100644
--- a/tests/tests/ObjectEncodingTest.php
+++ b/tests/tests/ObjectEncodingTest.php
@@ -9,7 +9,7 @@
/**
* @author Riikka Kalliomäki
- * @copyright Copyright (c) 2014-2017 Riikka Kalliomäki
+ * @copyright Copyright (c) 2014-2018 Riikka Kalliomäki
* @license http://opensource.org/licenses/mit-license.php MIT License
*/
class ObjectEncodingTest extends TestCase
@@ -28,7 +28,7 @@ public function testSerialize()
);
$evaluated = eval("return $code;");
- $this->assertSame(get_class($obj), get_class($evaluated));
+ $this->assertSame(\get_class($obj), \get_class($evaluated));
$this->assertSame((array) $obj, (array) $evaluated);
}
@@ -72,18 +72,18 @@ public function testPHP()
public function testObjectVarsArray()
{
$encoder = new PHPEncoder([
- 'whitespace' => false,
+ 'whitespace' => false,
'object.format' => 'vars',
- 'object.cast' => false,
+ 'object.cast' => false,
]);
$std = new \stdClass();
$std->baz = 'C';
$this->assertSame("['baz'=>'C']", $encoder->encode($std));
$this->assertSame("(object) [\n 'baz' => 'C',\n]", $encoder->encode($std, [
- 'object.cast' => true,
- 'whitespace' => true,
- 'array.eol' => "\n",
+ 'object.cast' => true,
+ 'whitespace' => true,
+ 'array.eol' => "\n",
'array.indent' => ' ',
]));
}
@@ -92,7 +92,7 @@ public function testObjectExport()
{
$encoder = new PHPEncoder([
'object.format' => 'export',
- 'whitespace' => false,
+ 'whitespace' => false,
]);
$obj = new ExtendsTestMockObject();
@@ -107,9 +107,9 @@ public function testObjectExport()
public function testIteratingArray()
{
$encoder = new PHPEncoder([
- 'whitespace' => false,
+ 'whitespace' => false,
'object.format' => 'iterate',
- 'object.cast' => false,
+ 'object.cast' => false,
]);
$array = ['foo' => 'bar', [1, 2], 3, 10 => 1337, 11 => 7, 6 => 6];
@@ -120,9 +120,9 @@ public function testIteratingArray()
public function testArrayCasting()
{
$encoder = new PHPEncoder([
- 'whitespace' => false,
+ 'whitespace' => false,
'object.format' => 'array',
- 'object.cast' => false,
+ 'object.cast' => false,
]);
$obj = new \stdClass();