From 4d7c89bfaf8d5897d67880fc643974d7850688b9 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Mon, 4 Apr 2016 14:34:08 +0200 Subject: [PATCH 01/12] [ValueExporter] extracted ValueExporter in its own component --- .../Component/ValueExporter/.gitignore | 3 + .../Component/ValueExporter/CHANGELOG.md | 7 ++ .../Exception/InvalidFormatterException.php | 31 +++++++ .../Exporter/AbstractValueExporter.php | 74 +++++++++++++++ .../Exporter/ValueExporterInterface.php | 53 +++++++++++ .../Exporter/ValueToStringExporter.php | 93 +++++++++++++++++++ .../Formatter/DateTimeToStringFormatter.php | 39 ++++++++ .../Formatter/FormatterInterface.php | 31 +++++++ .../PhpIncompleteClassToStringFormatter.php | 44 +++++++++ .../Formatter/StringFormatterInterface.php | 31 +++++++ .../Component/ValueExporter/LICENSE.txt | 19 ++++ src/Symfony/Component/ValueExporter/README.md | 16 ++++ .../Resources/functions/to_string.php | 23 +++++ .../ValueExporter/Tests/ValueExporterTest.php | 82 ++++++++++++++++ .../Component/ValueExporter/ValueExporter.php | 93 +++++++++++++++++++ .../Component/ValueExporter/composer.json | 49 ++++++++++ .../Component/ValueExporter/phpunit.xml.dist | 31 +++++++ 17 files changed, 719 insertions(+) create mode 100644 src/Symfony/Component/ValueExporter/.gitignore create mode 100644 src/Symfony/Component/ValueExporter/CHANGELOG.md create mode 100644 src/Symfony/Component/ValueExporter/Exception/InvalidFormatterException.php create mode 100644 src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php create mode 100644 src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php create mode 100644 src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php create mode 100644 src/Symfony/Component/ValueExporter/Formatter/DateTimeToStringFormatter.php create mode 100644 src/Symfony/Component/ValueExporter/Formatter/FormatterInterface.php create mode 100644 src/Symfony/Component/ValueExporter/Formatter/PhpIncompleteClassToStringFormatter.php create mode 100644 src/Symfony/Component/ValueExporter/Formatter/StringFormatterInterface.php create mode 100644 src/Symfony/Component/ValueExporter/LICENSE.txt create mode 100644 src/Symfony/Component/ValueExporter/README.md create mode 100644 src/Symfony/Component/ValueExporter/Resources/functions/to_string.php create mode 100644 src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php create mode 100644 src/Symfony/Component/ValueExporter/ValueExporter.php create mode 100644 src/Symfony/Component/ValueExporter/composer.json create mode 100644 src/Symfony/Component/ValueExporter/phpunit.xml.dist diff --git a/src/Symfony/Component/ValueExporter/.gitignore b/src/Symfony/Component/ValueExporter/.gitignore new file mode 100644 index 0000000000000..5414c2c655e72 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/src/Symfony/Component/ValueExporter/CHANGELOG.md b/src/Symfony/Component/ValueExporter/CHANGELOG.md new file mode 100644 index 0000000000000..58eb13c207df2 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +3.2.0 +----- + + * introducing the component diff --git a/src/Symfony/Component/ValueExporter/Exception/InvalidFormatterException.php b/src/Symfony/Component/ValueExporter/Exception/InvalidFormatterException.php new file mode 100644 index 0000000000000..a8ae16aa43680 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Exception/InvalidFormatterException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Exception; + +/** + * Thrown when a {@link \Symfony\Component\ValueExporter\Formatter\FormatterInterface} + * is not supported by the {@link \Symfony\Component\ValueExporter\Exporter\ValueExporterInterface}. + * + * @author Jules Pietri + */ +class InvalidFormatterException extends \InvalidArgumentException +{ + /** + * @param string $formatterClass The invalid formatter class + * @param string $exporterClass The exporter class + * @param string $expectedInterface The expected formatter interface + */ + public function __construct($formatterClass, $exporterClass, $expectedInterface) + { + parent::__construct(sprintf('The exporter "%s" expects formatters implementing "%", but was given "%s" class.', $exporterClass, $expectedInterface, $formatterClass)); + } +} diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php new file mode 100644 index 0000000000000..82d98f05a5cb1 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Exporter; + +use Symfony\Component\ValueExporter\Exception\InvalidFormatterException; +use Symfony\Component\ValueExporter\Formatter\FormatterInterface; + +/** + * ValueExporterInterface implementations export PHP values. + * + * @author Jules Pietri + */ +abstract class AbstractValueExporter implements ValueExporterInterface +{ + /** + * The supported formatter interface. + * + * @var string + */ + protected $formatterInterface = FormatterInterface::class; + + /** + * An array of formatters. + * + * @var FormatterInterface[] + */ + private $formatters = array(); + + /** + * Takes {@link FormatterInterface} as arguments. + * + * They will be called in the given order. + */ + final public function __construct() + { + $this->addFormatters(func_get_args()); + } + + /** + * {@inheritdoc} + */ + final public function addFormatters(array $appends, array $prepends = array()) + { + foreach ($appends as $append) { + if (!$append instanceof $this->formatterInterface) { + throw new InvalidFormatterException(get_class($append), self::class, $this->formatterInterface); + } + $this->formatters[] = $append; + } + foreach (array_reverse($prepends) as $prepend) { + if (!$prepend instanceof $this->formatterInterface) { + throw new InvalidFormatterException(get_class($prepend), self::class, $this->formatterInterface); + } + array_unshift($this->formatters, $prepend); + } + } + + /** + * @return FormatterInterface[] + */ + final protected function formatters() + { + return $this->formatters; + } +} diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php new file mode 100644 index 0000000000000..d055059fa9536 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Exporter; + +use Symfony\Component\ValueExporter\Exception\InvalidFormatterException; +use Symfony\Component\ValueExporter\Exporter; +use Symfony\Component\ValueExporter\Formatter\FormatterInterface; + +/** + * ValueExporterInterface implementations export PHP values. + * + * An implementation can rely on {@link FormatterInterface} implementations + * to handle specific types of value. + * + * @author Jules Pietri + */ +interface ValueExporterInterface +{ + /** + * Exports a PHP value. + * + * ValueExporter instance should always deal with array or \Traversable + * values first in order to handle depth and expand arguments. + * + * Usually you don't need to define the depth but it will be incremented + * in recursive calls. When expand is false any expandable values such as + * arrays or objects should be inline in their exported representation. + * + * @param mixed $value The PHP value to export + * @param int $depth The level of indentation + * @param bool $expand Whether to inline or expand nested values + */ + public function exportValue($value, $depth, $expand); + + /** + * Adds {@link FormatterInterface} that will be called in the given order. + * + * @param FormatterInterface[] $appends The formatters to execute at last + * @param FormatterInterface[] $prepends The formatters to execute first + * + * @throws InvalidFormatterException If the exporter does not support a given formatter + */ + public function addFormatters(array $appends, array $prepends); +} diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php new file mode 100644 index 0000000000000..71663d822eaef --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Exporter; + +use Symfony\Component\ValueExporter\Formatter\StringFormatterInterface; + +/** + * @author Fabien Potencier + * @author Bernhard Schussek + * @author Quentin Schuler + * @author Jules Pietri + */ +class ValueToStringExporter extends AbstractValueExporter +{ + protected $formatterInterface = StringFormatterInterface::class; + + public function exportValue($value, $depth = 1, $expand = false) + { + // Arrays have to be handled first to deal with nested level and depth, + // this implementation intentionally ignores \Traversable values. + // Therefor, \Traversable instances might be treated as objects unless + // implementing a {@link StringFormatterInterface} and passing it to + // the exporter in order to support them. + if (is_array($value)) { + if (empty($value)) { + return 'array()'; + } + $indent = str_repeat(' ', $depth); + + $a = array(); + foreach ($value as $k => $v) { + if (is_array($v) && !empty($v)) { + $expand = true; + } + $a[] = sprintf('%s => %s', is_string($k) ? sprintf("'%s'", $k) : $k, $this->exportValue($v, $depth + 1, $expand)); + } + if ($expand) { + return sprintf("array(\n%s%s\n%s)", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1)); + } + + $s = sprintf('array(%s)', implode(', ', $a)); + + if (80 > strlen($s)) { + return $s; + } + + return sprintf("array(\n%s%s\n)", $indent, implode(sprintf(",\n%s", $indent), $a)); + } + // Not an array, test each formatter + foreach ($this->formatters() as $formatter) { + /** @var StringFormatterInterface $formatter */ + if ($formatter->supports($value)) { + return $formatter->formatToString($value); + } + } + // Fallback on default + if (is_object($value)) { + return sprintf('object(%s)', get_class($value)); + } + if (is_resource($value)) { + return sprintf('resource(%s#%d)', get_resource_type($value), $value); + } + if (is_float($value)) { + return sprintf('(float) %s', $value); + } + if (is_int($value)) { + return sprintf('(int) %d', $value); + } + if (is_string($value)) { + return sprintf('"%s"', $value); + } + if (null === $value) { + return 'null'; + } + if (false === $value) { + return 'false'; + } + if (true === $value) { + return 'true'; + } + + return (string) $value; + } +} diff --git a/src/Symfony/Component/ValueExporter/Formatter/DateTimeToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/DateTimeToStringFormatter.php new file mode 100644 index 0000000000000..efa4b0b6ccc26 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/DateTimeToStringFormatter.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * Returns a string representation of a DateTimeInterface instance. + * + * Based on the contribution by @scuben (https://github.com/scuben) + * https://github.com/symfony/symfony/commit/a1762fb65423dc94d69c5fb6abaed37f2ad576e6 + * + * @author Jules Pietri + */ +class DateTimeToStringFormatter implements StringFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function supports($value) + { + return $value instanceof \DateTimeInterface; + } + + /** + * {@inheritdoc} + */ + public function formatToString($value) + { + return sprintf('object(%s) - %s', get_class($value), $value->format(\DateTime::ISO8601)); + } +} diff --git a/src/Symfony/Component/ValueExporter/Formatter/FormatterInterface.php b/src/Symfony/Component/ValueExporter/Formatter/FormatterInterface.php new file mode 100644 index 0000000000000..e32504905b05a --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/FormatterInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * FormatterInterface. + * + * Returns a formatted representation of (a) supported type(s) of PHP value. + * + * @author Jules Pietri + */ +interface FormatterInterface +{ + /** + * Returns whether the formatter can format the type(s) of the given value. + * + * @param mixed $value The given value to format + * + * @return bool Whether the given value can be formatted + */ + public function supports($value); +} diff --git a/src/Symfony/Component/ValueExporter/Formatter/PhpIncompleteClassToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/PhpIncompleteClassToStringFormatter.php new file mode 100644 index 0000000000000..b3ba602d1bed5 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/PhpIncompleteClassToStringFormatter.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * Returns a string representation of a __PHP_Incomplete_Class instance. + * + * @author Yonel Ceruto González + * @author Jules Pietri + */ +class PhpIncompleteClassToStringFormatter implements StringFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function supports($value) + { + return $value instanceof \__PHP_Incomplete_Class; + } + + /** + * {@inheritdoc} + */ + public function formatToString($value) + { + return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value)); + } + + private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) + { + $array = new \ArrayObject($value); + + return $array['__PHP_Incomplete_Class_Name']; + } +} diff --git a/src/Symfony/Component/ValueExporter/Formatter/StringFormatterInterface.php b/src/Symfony/Component/ValueExporter/Formatter/StringFormatterInterface.php new file mode 100644 index 0000000000000..8c6fa260e98a3 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/StringFormatterInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * StringFormatter. + * + * Returns a string representation of a given value. + * + * @author Jules Pietri + */ +interface StringFormatterInterface extends FormatterInterface +{ + /** + * Returns a given value formatted to string. + * + * @param mixed $value The given value to format to string + * + * @return string A string representation of the given value + */ + public function formatToString($value); +} diff --git a/src/Symfony/Component/ValueExporter/LICENSE.txt b/src/Symfony/Component/ValueExporter/LICENSE.txt new file mode 100644 index 0000000000000..0564c5a9b7f1f --- /dev/null +++ b/src/Symfony/Component/ValueExporter/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2016 Fabien Potencier + +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 the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Symfony/Component/ValueExporter/README.md b/src/Symfony/Component/ValueExporter/README.md new file mode 100644 index 0000000000000..cde83ef943a37 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/README.md @@ -0,0 +1,16 @@ +ValueExporter Component +======================= + +The ValueExporter component provides mechanisms to export any arbitrary +PHP variable in a desired format. Built on top, it provides a `to_string()` +function that you can safely use instead of casting `(string) $value`, finely +represented thanks to formatters. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/value_exporter/introduction.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/src/Symfony/Component/ValueExporter/Resources/functions/to_string.php b/src/Symfony/Component/ValueExporter/Resources/functions/to_string.php new file mode 100644 index 0000000000000..367fca038e77b --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Resources/functions/to_string.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\ValueExporter\ValueExporter; + +if (!function_exists('to_string')) { + /** + * @author Nicolas Grekas + * @author Jules Pietri + */ + function to_string($value, $depth = 1, $expand = false) + { + return ValueExporter::export($value, $depth, $expand); + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php new file mode 100644 index 0000000000000..ecb4b5fcfa6b7 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests; + +use Symfony\Component\ValueExporter\ValueExporter; + +class ValueExporterTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider valueProvider + */ + public function testExportValue($value, $string) + { + $this->assertSame($string, ValueExporter::export($value)); + } + + /** + * @dataProvider valueProvider + */ + public function testToStringFunctionWrapper($value, $string) + { + $this->assertSame($string, to_string($value)); + } + + public function testExportValueExpanded() + { + $value = array( + array(ValueExporter::class, 'export'), + ); + + $exportedValue = << array(0 => "Symfony\Component\ValueExporter\ValueExporter", 1 => "export") +) +EOT; + + $this->assertSame($exportedValue, ValueExporter::export($value, 1, true)); + } + + public function valueProvider() + { + $foo = new \__PHP_Incomplete_Class(); + $array = new \ArrayObject($foo); + $array['__PHP_Incomplete_Class_Name'] = 'AppBundle/Foo'; + + return array( + 'null' => array(null, 'null'), + 'true' => array(true, 'true'), + 'false' => array(false, 'false'), + 'int' => array(4, '(int) 4'), + 'float' => array(4.5, '(float) 4.5'), + 'string' => array('test', '"test"'), + 'empty array' => array(array(), 'array()'), + 'numeric array' => array( + array(0 => null, 1 => true, 2 => 1, 3 => '2', 4 => new \stdClass()), + 'array(0 => null, 1 => true, 2 => (int) 1, 3 => "2", 4 => object(stdClass))', + ), + 'mixed keys array' => array( + array(0 => 0, '1' => 'un', 'key' => 4.5), + 'array(0 => (int) 0, 1 => "un", \'key\' => (float) 4.5)', + ), + 'datetime' => array( + new \DateTime('2014-06-10 07:35:40', new \DateTimeZone('UTC')), + 'object(DateTime) - 2014-06-10T07:35:40+0000', + ), + 'datetime immutable' => array( + new \DateTimeImmutable('2014-06-10 07:35:40', new \DateTimeZone('UTC')), + 'object(DateTimeImmutable) - 2014-06-10T07:35:40+0000', + ), + 'php incomplete class' => array($foo, '__PHP_Incomplete_Class(AppBundle/Foo)'), + ); + } +} diff --git a/src/Symfony/Component/ValueExporter/ValueExporter.php b/src/Symfony/Component/ValueExporter/ValueExporter.php new file mode 100644 index 0000000000000..cbb242984b780 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/ValueExporter.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter; + +use Symfony\Component\ValueExporter\Exporter\ValueExporterInterface; +use Symfony\Component\ValueExporter\Exporter\ValueToStringExporter; +use Symfony\Component\ValueExporter\Formatter\DateTimeToStringFormatter; +use Symfony\Component\ValueExporter\Formatter\FormatterInterface; +use Symfony\Component\ValueExporter\Formatter\PhpIncompleteClassToStringFormatter; + +// Load the global to_string() function +require_once __DIR__.'/Resources/functions/to_string.php'; + +/** + * @author Nicolas Grekas + * @author Jules Pietri + */ +class ValueExporter +{ + private static $handler; + private static $exporter; + private static $appends = array(); + private static $prepends = array(); + + public static function export($value, $depth = 1, $expand = false) + { + if (null === self::$handler) { + $exporter = self::$exporter ?: new ValueToStringExporter( + new DateTimeToStringFormatter(), + new PhpIncompleteClassToStringFormatter() + ); + $exporter->addFormatters(self::$appends, self::$prepends); + // Clear extra formatters + self::$appends = self::$prepends = array(); + self::$handler = function ($value, $depth = 1, $expand = false) use ($exporter) { + return $exporter->exportValue($value, $depth, $expand); + }; + } + + return call_user_func(self::$handler, $value, $depth, $expand); + } + + public static function setHandler(callable $callable = null) + { + $prevHandler = self::$handler; + self::$handler = $callable; + + return $prevHandler; + } + + /** + * Sets a new {@link ValueExporterInterface} instance as exporter. + * + * @param ValueExporterInterface $exporter The exporter instance + */ + public static function setExporter(ValueExporterInterface $exporter) + { + self::$handler = null; + self::$exporter = $exporter; + self::$appends = self:: $prepends = array(); + } + + /** + * Appends a {@link FormatterInterface} to the {@link ValueExporterInterface}. + * + * @param FormatterInterface $formatter + */ + public static function appendFormatter(FormatterInterface $formatter) + { + self::$handler = null; + self::$appends[] = $formatter; + } + + /** + * Prepends a {@link FormatterInterface} to the {@link ValueExporterInterface}. + * + * @param FormatterInterface $formatter + */ + public static function prependFormatter(FormatterInterface $formatter) + { + self::$handler = null; + self::$prepends[] = $formatter; + } +} diff --git a/src/Symfony/Component/ValueExporter/composer.json b/src/Symfony/Component/ValueExporter/composer.json new file mode 100644 index 0000000000000..48a6b310ecf79 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/composer.json @@ -0,0 +1,49 @@ +{ + "name": "symfony/value-exporter", + "type": "library", + "description": "Symfony mechanism for formatting PHP variables", + "keywords": ["export", "php values", "logs"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Jules Pietri", + "email": "jules@heahprod.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=5.5.9" + }, + "suggest": { + "symfony/var-dumper": "To dump PHP values" + }, + "autoload": { + "files": [ "Resources/functions/to_string.php" ], + "psr-4": { "Symfony\\Component\\ValueExporter\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + } +} diff --git a/src/Symfony/Component/ValueExporter/phpunit.xml.dist b/src/Symfony/Component/ValueExporter/phpunit.xml.dist new file mode 100644 index 0000000000000..4e1bb0a660cd4 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + + + + + + + ./Tests/ + + + + + + ./ + + ./Resources + ./Tests + ./vendor + + + + From afadb5bb3c4bce726147455bc90a7386cda0d345 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Tue, 5 Apr 2016 19:42:38 +0200 Subject: [PATCH 02/12] [ValueExporter] added CallableToStringFormatter --- .../Exporter/ValueToStringExporter.php | 2 +- .../Formatter/CallableToStringFormatter.php | 50 +++++++++++++++++++ .../ValueExporter/Tests/ValueExporterTest.php | 14 +++++- .../Component/ValueExporter/ValueExporter.php | 2 + 4 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php index 71663d822eaef..5a0374caf4054 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php @@ -30,7 +30,7 @@ public function exportValue($value, $depth = 1, $expand = false) // Therefor, \Traversable instances might be treated as objects unless // implementing a {@link StringFormatterInterface} and passing it to // the exporter in order to support them. - if (is_array($value)) { + if (is_array($value) && !is_callable($value)) { if (empty($value)) { return 'array()'; } diff --git a/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php new file mode 100644 index 0000000000000..075d2b8d77a1a --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * Returns a string representation of a string or array callable. + * + * @author Jules Pietri + */ +class CallableToStringFormatter implements StringFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function supports($value) + { + return is_callable($value) && !$value instanceof \Closure; + } + + /** + * {@inheritdoc} + */ + public function formatToString($value) + { + if (is_string($value)) { + return sprintf('(function) "%s"', $value); + } + + $caller = is_object($value) ? get_class($value) : (is_object($value[0]) ? get_class($value[0]) : $value[0]); + if (is_object($value)) { + return sprintf('(invokable) "%s"', $caller); + } + + $method = $value[1]; + if (false !== $cut = strpos($method, $caller)) { + $method = substr($method, $cut); + } + + return sprintf('(callable) "%s::%s"', $caller, $method); + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index ecb4b5fcfa6b7..26c6af7397e5f 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -39,7 +39,7 @@ public function testExportValueExpanded() $exportedValue = << array(0 => "Symfony\Component\ValueExporter\ValueExporter", 1 => "export") + 0 => (callable) "Symfony\Component\ValueExporter\ValueExporter::export" ) EOT; @@ -68,6 +68,13 @@ public function valueProvider() array(0 => 0, '1' => 'un', 'key' => 4.5), 'array(0 => (int) 0, 1 => "un", \'key\' => (float) 4.5)', ), + 'closure' => array(function() {}, 'object(Closure)'), + 'callable string' => array('strlen', '(function) "strlen"'), + 'callable array' => array( + array($this, 'testExportValue'), + '(callable) "Symfony\Component\ValueExporter\Tests\ValueExporterTest::testExportValue"', + ), + 'invokable object' => array($this, '(invokable) "Symfony\Component\ValueExporter\Tests\ValueExporterTest"'), 'datetime' => array( new \DateTime('2014-06-10 07:35:40', new \DateTimeZone('UTC')), 'object(DateTime) - 2014-06-10T07:35:40+0000', @@ -79,4 +86,9 @@ public function valueProvider() 'php incomplete class' => array($foo, '__PHP_Incomplete_Class(AppBundle/Foo)'), ); } + + public function __invoke() + { + return 'TEST'; + } } diff --git a/src/Symfony/Component/ValueExporter/ValueExporter.php b/src/Symfony/Component/ValueExporter/ValueExporter.php index cbb242984b780..6460cb33d8e11 100644 --- a/src/Symfony/Component/ValueExporter/ValueExporter.php +++ b/src/Symfony/Component/ValueExporter/ValueExporter.php @@ -13,6 +13,7 @@ use Symfony\Component\ValueExporter\Exporter\ValueExporterInterface; use Symfony\Component\ValueExporter\Exporter\ValueToStringExporter; +use Symfony\Component\ValueExporter\Formatter\CallableToStringFormatter; use Symfony\Component\ValueExporter\Formatter\DateTimeToStringFormatter; use Symfony\Component\ValueExporter\Formatter\FormatterInterface; use Symfony\Component\ValueExporter\Formatter\PhpIncompleteClassToStringFormatter; @@ -35,6 +36,7 @@ public static function export($value, $depth = 1, $expand = false) { if (null === self::$handler) { $exporter = self::$exporter ?: new ValueToStringExporter( + new CallableToStringFormatter(), new DateTimeToStringFormatter(), new PhpIncompleteClassToStringFormatter() ); From 4eeb80070317583b1eb6f8b55b29d6b6ef9b7467 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 9 Apr 2016 04:31:32 +0200 Subject: [PATCH 03/12] [ValueExporter] added abstract ExpandedFormatter --- .../Exporter/AbstractValueExporter.php | 7 +++ .../Formatter/ExpandedFormatter.php | 44 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index 82d98f05a5cb1..745068a2690a3 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\ValueExporter\Exporter; use Symfony\Component\ValueExporter\Exception\InvalidFormatterException; +use Symfony\Component\ValueExporter\Formatter\ExpandedFormatter; use Symfony\Component\ValueExporter\Formatter\FormatterInterface; /** @@ -54,12 +55,18 @@ final public function addFormatters(array $appends, array $prepends = array()) if (!$append instanceof $this->formatterInterface) { throw new InvalidFormatterException(get_class($append), self::class, $this->formatterInterface); } + if ($append instanceof ExpandedFormatter) { + $append->setExporter($this); + } $this->formatters[] = $append; } foreach (array_reverse($prepends) as $prepend) { if (!$prepend instanceof $this->formatterInterface) { throw new InvalidFormatterException(get_class($prepend), self::class, $this->formatterInterface); } + if ($prepend instanceof ExpandedFormatter) { + $prepend->setExporter($this); + } array_unshift($this->formatters, $prepend); } } diff --git a/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php new file mode 100644 index 0000000000000..0157f98a536a7 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +use Symfony\Component\ValueExporter\Exporter\ValueExporterInterface; + +/** + * ExpandedFormatter. + * + * An abstract class holding the {@link ValueExporterInterface} to export nested values. + * + * @author Jules Pietri + */ +abstract class ExpandedFormatter +{ + /** + * @var ValueExporterInterface + */ + private $exporter; + + /** + * Sets the exporter to call on nested values. + * + * @param ValueExporterInterface $exporter The exporter + */ + final public function setExporter(ValueExporterInterface $exporter) + { + $this->exporter = $exporter; + } + + final protected function export($value) + { + return $this->exporter->exportValue($value, 1, false); + } +} From 845aea1f65b20ab895e0aa61872dff3c08a02968 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 9 Apr 2016 12:56:37 +0200 Subject: [PATCH 04/12] [ValueExporter] added TraversableToStringFormatter --- .../TraversableToStringFormatter.php | 41 +++++++++++++++++++ .../Tests/Fixtures/TraversableInstance.php | 31 ++++++++++++++ .../ValueExporter/Tests/ValueExporterTest.php | 17 ++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php create mode 100644 src/Symfony/Component/ValueExporter/Tests/Fixtures/TraversableInstance.php diff --git a/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php new file mode 100644 index 0000000000000..96e6f40a245a7 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * Returns a string representation of an instance implementing \Traversable. + * + * @author Jules Pietri + */ +class TraversableToStringFormatter extends ExpandedFormatter implements StringFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function supports($value) + { + return $value instanceof \Traversable; + } + + /** + * {@inheritdoc} + */ + public function formatToString($value) + { + $nested = array(); + foreach ($value as $k => $v) { + $nested[] = sprintf('%s => %s', is_string($k) ? sprintf("'%s'", $k) : $k, $this->export($v)); + } + + return sprintf("Traversable:\"%s\"(\n %s\n)", get_class($value), implode(",\n ", $nested)); + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/Fixtures/TraversableInstance.php b/src/Symfony/Component/ValueExporter/Tests/Fixtures/TraversableInstance.php new file mode 100644 index 0000000000000..6a3bfc32a2aed --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/Fixtures/TraversableInstance.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests\Fixtures; + +/** + * TraversableInstance. + * + * @author Jules Pietri + */ +class TraversableInstance implements \IteratorAggregate +{ + public $property1 = 'value1'; + public $property2 = 'value2'; + + /** + * {@inheritdoc} + */ + public function getIterator() + { + return new \ArrayIterator($this); + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index 26c6af7397e5f..ea04899be4d66 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -11,6 +11,8 @@ namespace Symfony\Component\ValueExporter\Tests; +use Symfony\Component\ValueExporter\Formatter\TraversableToStringFormatter; +use Symfony\Component\ValueExporter\Tests\Fixtures\TraversableInstance; use Symfony\Component\ValueExporter\ValueExporter; class ValueExporterTest extends \PHPUnit_Framework_TestCase @@ -46,6 +48,21 @@ public function testExportValueExpanded() $this->assertSame($exportedValue, ValueExporter::export($value, 1, true)); } + public function testExportTraversable() + { + ValueExporter::appendFormatter(new TraversableToStringFormatter()); + + $value = new TraversableInstance(); + $exportedValue = << "value1", + 'property2' => "value2" +) +EOT; + + $this->assertSame($exportedValue, ValueExporter::export($value)); + } + public function valueProvider() { $foo = new \__PHP_Incomplete_Class(); From 438b845a58c8a6daa56acb7513776893d83a6a6b Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Mon, 18 Apr 2016 08:41:44 +0200 Subject: [PATCH 05/12] [ValueExporter] added EntityToStringFormatter --- .../Formatter/EntityToStringFormatter.php | 44 +++++++++++++++++++ .../ValueExporter/Tests/Fixtures/Entity.php | 32 ++++++++++++++ .../Tests/Fixtures/PublicEntity.php | 27 ++++++++++++ .../ValueExporter/Tests/ValueExporterTest.php | 4 ++ .../Component/ValueExporter/ValueExporter.php | 2 + 5 files changed, 109 insertions(+) create mode 100644 src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php create mode 100644 src/Symfony/Component/ValueExporter/Tests/Fixtures/Entity.php create mode 100644 src/Symfony/Component/ValueExporter/Tests/Fixtures/PublicEntity.php diff --git a/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php new file mode 100644 index 0000000000000..45f5bbf957833 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Formatter; + +/** + * Returns a string representation of a DateTimeInterface instance. + * + * Based on the contribution by @scuben (https://github.com/scuben) + * https://github.com/symfony/symfony/commit/a1762fb65423dc94d69c5fb6abaed37f2ad576e6 + * + * @author Jules Pietri + */ +class EntityToStringFormatter implements StringFormatterInterface +{ + /** + * {@inheritdoc} + */ + public function supports($value) + { + return is_object($value) + && !$value instanceof \Closure + && (isset($value->id) || is_callable(array($value, 'id')) || is_callable(array($value, 'getId'))) + ; + } + + /** + * {@inheritdoc} + */ + public function formatToString($value) + { + $id = isset($value->id) ? $value->id : (is_callable(array($value, 'id')) ? $value->id() : $value->getId()); + + return sprintf('entity:%s(%s)', $id, get_class($value)); + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/Fixtures/Entity.php b/src/Symfony/Component/ValueExporter/Tests/Fixtures/Entity.php new file mode 100644 index 0000000000000..06c38e984552a --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/Fixtures/Entity.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests\Fixtures; + +/** + * Entity with an id getter. + * + * @author Jules Pietri + */ +class Entity +{ + private $id; + + public function __construct($id) + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/Fixtures/PublicEntity.php b/src/Symfony/Component/ValueExporter/Tests/Fixtures/PublicEntity.php new file mode 100644 index 0000000000000..310dd32b716a6 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/Fixtures/PublicEntity.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests\Fixtures; + +/** + * Entity with a public id. + * + * @author Jules Pietri + */ +class PublicEntity +{ + public $id; + + public function __construct($id) + { + $this->id = $id; + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index ea04899be4d66..34983e16276eb 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -12,6 +12,8 @@ namespace Symfony\Component\ValueExporter\Tests; use Symfony\Component\ValueExporter\Formatter\TraversableToStringFormatter; +use Symfony\Component\ValueExporter\Tests\Fixtures\Entity; +use Symfony\Component\ValueExporter\Tests\Fixtures\PublicEntity; use Symfony\Component\ValueExporter\Tests\Fixtures\TraversableInstance; use Symfony\Component\ValueExporter\ValueExporter; @@ -101,6 +103,8 @@ public function valueProvider() 'object(DateTimeImmutable) - 2014-06-10T07:35:40+0000', ), 'php incomplete class' => array($foo, '__PHP_Incomplete_Class(AppBundle/Foo)'), + 'entity' => array(new Entity(23), 'entity:23(Symfony\Component\ValueExporter\Tests\Fixtures\Entity)'), + 'public entity' => array(new PublicEntity(23), 'entity:23(Symfony\Component\ValueExporter\Tests\Fixtures\PublicEntity)'), ); } diff --git a/src/Symfony/Component/ValueExporter/ValueExporter.php b/src/Symfony/Component/ValueExporter/ValueExporter.php index 6460cb33d8e11..067620acfebe6 100644 --- a/src/Symfony/Component/ValueExporter/ValueExporter.php +++ b/src/Symfony/Component/ValueExporter/ValueExporter.php @@ -15,6 +15,7 @@ use Symfony\Component\ValueExporter\Exporter\ValueToStringExporter; use Symfony\Component\ValueExporter\Formatter\CallableToStringFormatter; use Symfony\Component\ValueExporter\Formatter\DateTimeToStringFormatter; +use Symfony\Component\ValueExporter\Formatter\EntityToStringFormatter; use Symfony\Component\ValueExporter\Formatter\FormatterInterface; use Symfony\Component\ValueExporter\Formatter\PhpIncompleteClassToStringFormatter; @@ -38,6 +39,7 @@ public static function export($value, $depth = 1, $expand = false) $exporter = self::$exporter ?: new ValueToStringExporter( new CallableToStringFormatter(), new DateTimeToStringFormatter(), + new EntityToStringFormatter(), new PhpIncompleteClassToStringFormatter() ); $exporter->addFormatters(self::$appends, self::$prepends); From eb1a34d4b3e50d32c679208cc6b878d5b6b50fc8 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Thu, 21 Apr 2016 13:58:35 +0200 Subject: [PATCH 06/12] [ValueExporter] added priority to formatters --- .../Exporter/AbstractValueExporter.php | 49 ++++++++++++------- .../Exporter/ValueExporterInterface.php | 7 ++- .../ValueExporter/Tests/ValueExporterTest.php | 2 +- .../Component/ValueExporter/ValueExporter.php | 40 +++++++-------- 4 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index 745068a2690a3..65a439086ec84 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -30,12 +30,19 @@ abstract class AbstractValueExporter implements ValueExporterInterface protected $formatterInterface = FormatterInterface::class; /** - * An array of formatters. + * An array of arrays of formatters by priority. * - * @var FormatterInterface[] + * @var array[] */ private $formatters = array(); + /** + * A sorted array of formatters. + * + * @var FormatterInterface[] + */ + private $sortedFormatters; + /** * Takes {@link FormatterInterface} as arguments. * @@ -49,25 +56,26 @@ final public function __construct() /** * {@inheritdoc} */ - final public function addFormatters(array $appends, array $prepends = array()) + final public function addFormatters(array $formatters) { - foreach ($appends as $append) { - if (!$append instanceof $this->formatterInterface) { - throw new InvalidFormatterException(get_class($append), self::class, $this->formatterInterface); - } - if ($append instanceof ExpandedFormatter) { - $append->setExporter($this); + $this->sortedFormatters = null; + + foreach ($formatters as $formatter) { + if (is_array($formatter)) { + $priority = (int) $formatter[1]; + $formatter = $formatter[0]; + } else { + $priority = 0; } - $this->formatters[] = $append; - } - foreach (array_reverse($prepends) as $prepend) { - if (!$prepend instanceof $this->formatterInterface) { - throw new InvalidFormatterException(get_class($prepend), self::class, $this->formatterInterface); + if (!$formatter instanceof $this->formatterInterface) { + throw new InvalidFormatterException(get_class($formatter), self::class, $this->formatterInterface); } - if ($prepend instanceof ExpandedFormatter) { - $prepend->setExporter($this); + if ($formatter instanceof ExpandedFormatter) { + $formatter->setExporter($this); } - array_unshift($this->formatters, $prepend); + + // Using the class as key prevents duplicate + $this->formatters[$priority][get_class($formatter)] = $formatter; } } @@ -76,6 +84,11 @@ final public function addFormatters(array $appends, array $prepends = array()) */ final protected function formatters() { - return $this->formatters; + if (null === $this->sortedFormatters) { + krsort($this->formatters); + $this->sortedFormatters = call_user_func_array('array_merge', $this->formatters); + } + + return $this->sortedFormatters; } } diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php index d055059fa9536..8342f9e820d7b 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php @@ -42,12 +42,11 @@ interface ValueExporterInterface public function exportValue($value, $depth, $expand); /** - * Adds {@link FormatterInterface} that will be called in the given order. + * Adds {@link FormatterInterface} that will be called by priority. * - * @param FormatterInterface[] $appends The formatters to execute at last - * @param FormatterInterface[] $prepends The formatters to execute first + * @param (FormatterInterface|array)[] $formatters * * @throws InvalidFormatterException If the exporter does not support a given formatter */ - public function addFormatters(array $appends, array $prepends); + public function addFormatters(array $formatters); } diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index 34983e16276eb..fbff728b6a15e 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -52,7 +52,7 @@ public function testExportValueExpanded() public function testExportTraversable() { - ValueExporter::appendFormatter(new TraversableToStringFormatter()); + ValueExporter::addFormatters(array(new TraversableToStringFormatter())); $value = new TraversableInstance(); $exportedValue = <<addFormatters(self::$appends, self::$prepends); - // Clear extra formatters - self::$appends = self::$prepends = array(); + $exporter->addFormatters(self::$formatters); + // Clear formatters + self::$formatters = array(); self::$handler = function ($value, $depth = 1, $expand = false) use ($exporter) { return $exporter->exportValue($value, $depth, $expand); }; @@ -70,28 +69,29 @@ public static function setExporter(ValueExporterInterface $exporter) { self::$handler = null; self::$exporter = $exporter; - self::$appends = self:: $prepends = array(); + self::$formatters = array(); } /** - * Appends a {@link FormatterInterface} to the {@link ValueExporterInterface}. + * Adds {@link FormatterInterface} to the {@link ValueExporterInterface}. * - * @param FormatterInterface $formatter - */ - public static function appendFormatter(FormatterInterface $formatter) - { - self::$handler = null; - self::$appends[] = $formatter; - } - - /** - * Prepends a {@link FormatterInterface} to the {@link ValueExporterInterface}. + * You can simple pass an instance or an array with the instance and the priority: * - * @param FormatterInterface $formatter + * + * ValueExporter::addFormatters(array( + * new AcmeFormatter, + * array(new AcmeOtherFormatter(), 10) + * ); + * + * + * @param mixed $formatters An array of FormatterInterface instances and/or + * arrays holding an instance and its priority */ - public static function prependFormatter(FormatterInterface $formatter) + public static function addFormatters($formatters) { self::$handler = null; - self::$prepends[] = $formatter; + foreach ($formatters as $formatter) { + self::$formatters[] = $formatter; + } } } From 0e066a14aa3c2af5d90429a371418be92bd66d04 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Thu, 21 Apr 2016 17:09:02 +0200 Subject: [PATCH 07/12] [ValueExporter] made ExpandedFormatter a trait --- .../Exporter/AbstractValueExporter.php | 21 +++++++++++++++---- .../Exporter/ValueExporterInterface.php | 2 +- .../Exporter/ValueToStringExporter.php | 10 +++++++-- ...rmatter.php => ExpandedFormatterTrait.php} | 11 +++++++--- .../TraversableToStringFormatter.php | 4 +++- 5 files changed, 37 insertions(+), 11 deletions(-) rename src/Symfony/Component/ValueExporter/Formatter/{ExpandedFormatter.php => ExpandedFormatterTrait.php} (74%) diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index 65a439086ec84..634b1cbf2b1bb 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -12,7 +12,7 @@ namespace Symfony\Component\ValueExporter\Exporter; use Symfony\Component\ValueExporter\Exception\InvalidFormatterException; -use Symfony\Component\ValueExporter\Formatter\ExpandedFormatter; +use Symfony\Component\ValueExporter\Formatter\ExpandedFormatterTrait; use Symfony\Component\ValueExporter\Formatter\FormatterInterface; /** @@ -22,6 +22,15 @@ */ abstract class AbstractValueExporter implements ValueExporterInterface { + /** + * @var int + */ + protected $depth; + /** + * @var bool + */ + protected $expand; + /** * The supported formatter interface. * @@ -67,15 +76,19 @@ final public function addFormatters(array $formatters) } else { $priority = 0; } + + $formatterClass = get_class($formatter); + if (!$formatter instanceof $this->formatterInterface) { - throw new InvalidFormatterException(get_class($formatter), self::class, $this->formatterInterface); + throw new InvalidFormatterException($formatterClass, self::class, $this->formatterInterface); } - if ($formatter instanceof ExpandedFormatter) { + + if (in_array(ExpandedFormatterTrait::class, class_uses($formatterClass), true)) { $formatter->setExporter($this); } // Using the class as key prevents duplicate - $this->formatters[$priority][get_class($formatter)] = $formatter; + $this->formatters[$priority][$formatterClass] = $formatter; } } diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php index 8342f9e820d7b..cdc9275a72637 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueExporterInterface.php @@ -39,7 +39,7 @@ interface ValueExporterInterface * @param int $depth The level of indentation * @param bool $expand Whether to inline or expand nested values */ - public function exportValue($value, $depth, $expand); + public function exportValue($value, $depth = 1, $expand = false); /** * Adds {@link FormatterInterface} that will be called by priority. diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php index 5a0374caf4054..e6fbcc9f124a2 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php @@ -25,6 +25,9 @@ class ValueToStringExporter extends AbstractValueExporter public function exportValue($value, $depth = 1, $expand = false) { + // Use set properties for recursive calls + $depth = null === $this->depth ? $depth : $this->depth; + $expand = null === $this->expand ? $expand : $this->expand; // Arrays have to be handled first to deal with nested level and depth, // this implementation intentionally ignores \Traversable values. // Therefor, \Traversable instances might be treated as objects unless @@ -39,9 +42,12 @@ public function exportValue($value, $depth = 1, $expand = false) $a = array(); foreach ($value as $k => $v) { if (is_array($v) && !empty($v)) { - $expand = true; + $this->expand = true; + $this->depth = $depth + 1; } - $a[] = sprintf('%s => %s', is_string($k) ? sprintf("'%s'", $k) : $k, $this->exportValue($v, $depth + 1, $expand)); + $a[] = sprintf('%s => %s', is_string($k) ? sprintf("'%s'", $k) : $k, $this->exportValue($v)); + $this->depth = null; + $this->expand = null; } if ($expand) { return sprintf("array(\n%s%s\n%s)", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1)); diff --git a/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatterTrait.php similarity index 74% rename from src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php rename to src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatterTrait.php index 0157f98a536a7..24816b818d25d 100644 --- a/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatter.php +++ b/src/Symfony/Component/ValueExporter/Formatter/ExpandedFormatterTrait.php @@ -16,11 +16,11 @@ /** * ExpandedFormatter. * - * An abstract class holding the {@link ValueExporterInterface} to export nested values. + * A trait holding the {@link ValueExporterInterface} to export nested values. * * @author Jules Pietri */ -abstract class ExpandedFormatter +trait ExpandedFormatterTrait { /** * @var ValueExporterInterface @@ -37,8 +37,13 @@ final public function setExporter(ValueExporterInterface $exporter) $this->exporter = $exporter; } + /** + * @param mixed $value The nested value to export + * + * @return mixed The exported nested value + */ final protected function export($value) { - return $this->exporter->exportValue($value, 1, false); + return $this->exporter->exportValue($value); } } diff --git a/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php index 96e6f40a245a7..db45b5d193637 100644 --- a/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php +++ b/src/Symfony/Component/ValueExporter/Formatter/TraversableToStringFormatter.php @@ -16,8 +16,10 @@ * * @author Jules Pietri */ -class TraversableToStringFormatter extends ExpandedFormatter implements StringFormatterInterface +class TraversableToStringFormatter implements StringFormatterInterface { + use ExpandedFormatterTrait; + /** * {@inheritdoc} */ From 677c3c267c6f73d23d7589dde221509d6afd1324 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Thu, 21 Apr 2016 17:10:43 +0200 Subject: [PATCH 08/12] [ValueExporter] fixed class name's late static bind in AbstractValueExporter --- .../Component/ValueExporter/Exporter/AbstractValueExporter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index 634b1cbf2b1bb..52f613ecd4679 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -80,7 +80,7 @@ final public function addFormatters(array $formatters) $formatterClass = get_class($formatter); if (!$formatter instanceof $this->formatterInterface) { - throw new InvalidFormatterException($formatterClass, self::class, $this->formatterInterface); + throw new InvalidFormatterException($formatterClass, static::class, $this->formatterInterface); } if (in_array(ExpandedFormatterTrait::class, class_uses($formatterClass), true)) { From 8f63b0786164a7f456d8b6ba5ffd10b9d69c8796 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Thu, 21 Apr 2016 19:47:51 +0200 Subject: [PATCH 09/12] [ValueExporter] added support for formatters FQCN instead of instances --- .../Exporter/AbstractValueExporter.php | 49 +++++++++++++------ .../ValueExporter/Tests/ValueExporterTest.php | 2 +- .../Component/ValueExporter/ValueExporter.php | 8 +-- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index 52f613ecd4679..f7ee40e18295e 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -39,19 +39,26 @@ abstract class AbstractValueExporter implements ValueExporterInterface protected $formatterInterface = FormatterInterface::class; /** - * An array of arrays of formatters by priority. + * An array of priorities by formatter class. * * @var array[] */ private $formatters = array(); /** - * A sorted array of formatters. + * An array of formatters instances sorted by priority or null. * - * @var FormatterInterface[] + * @var FormatterInterface[]|null */ private $sortedFormatters; + /** + * An array of cached formatters instances by class. + * + * @var FormatterInterface[] + */ + private $cachedFormatters = array(); + /** * Takes {@link FormatterInterface} as arguments. * @@ -72,23 +79,19 @@ final public function addFormatters(array $formatters) foreach ($formatters as $formatter) { if (is_array($formatter)) { $priority = (int) $formatter[1]; - $formatter = $formatter[0]; + $formatterClass = $formatter[0]; } else { $priority = 0; + $formatterClass = $formatter; } - $formatterClass = get_class($formatter); - - if (!$formatter instanceof $this->formatterInterface) { + if (!in_array($this->formatterInterface, class_implements($formatterClass), true)) { throw new InvalidFormatterException($formatterClass, static::class, $this->formatterInterface); } - if (in_array(ExpandedFormatterTrait::class, class_uses($formatterClass), true)) { - $formatter->setExporter($this); - } - - // Using the class as key prevents duplicate - $this->formatters[$priority][$formatterClass] = $formatter; + // Using the class as key prevents duplicate and allows to + // dynamically change the priority + $this->formatters[$formatterClass] = $priority; } } @@ -98,8 +101,24 @@ final public function addFormatters(array $formatters) final protected function formatters() { if (null === $this->sortedFormatters) { - krsort($this->formatters); - $this->sortedFormatters = call_user_func_array('array_merge', $this->formatters); + arsort($this->formatters); + + foreach (array_keys($this->formatters) as $formatterClass) { + if (isset($this->cachedFormatters[$formatterClass])) { + $this->sortedFormatters[] = $this->cachedFormatters[$formatterClass]; + + continue; + } + + $formatter = new $formatterClass(); + + if (in_array(ExpandedFormatterTrait::class, class_uses($formatterClass), true)) { + /* @var ExpandedFormatterTrait $formatter */ + $formatter->setExporter($this); + } + + $this->sortedFormatters[] = $this->cachedFormatters[$formatterClass] = $formatter; + } } return $this->sortedFormatters; diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index fbff728b6a15e..831ee4e9001ae 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -52,7 +52,7 @@ public function testExportValueExpanded() public function testExportTraversable() { - ValueExporter::addFormatters(array(new TraversableToStringFormatter())); + ValueExporter::addFormatters(array(TraversableToStringFormatter::class)); $value = new TraversableInstance(); $exportedValue = <<addFormatters(self::$formatters); // Clear formatters From a83684c6d0643f2c97c4da02973a9fec4a9200c7 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 23 Apr 2016 08:15:48 +0200 Subject: [PATCH 10/12] [ValueExporter] added support for objects implementing __toString() --- .../Exporter/ValueToStringExporter.php | 4 +++ .../Formatter/EntityToStringFormatter.php | 4 +++ .../Fixtures/EntityImplementingToString.php | 34 +++++++++++++++++++ .../Fixtures/ObjectImplementingToString.php | 32 +++++++++++++++++ .../ValueExporter/Tests/ValueExporterTest.php | 10 ++++++ 5 files changed, 84 insertions(+) create mode 100644 src/Symfony/Component/ValueExporter/Tests/Fixtures/EntityImplementingToString.php create mode 100644 src/Symfony/Component/ValueExporter/Tests/Fixtures/ObjectImplementingToString.php diff --git a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php index e6fbcc9f124a2..480c6bf7a5abb 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/ValueToStringExporter.php @@ -70,6 +70,10 @@ public function exportValue($value, $depth = 1, $expand = false) } // Fallback on default if (is_object($value)) { + if (method_exists($value, '__toString')) { + return sprintf('object(%s) "%s"', get_class($value), $value); + } + return sprintf('object(%s)', get_class($value)); } if (is_resource($value)) { diff --git a/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php index 45f5bbf957833..162fc2fe0dd22 100644 --- a/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php +++ b/src/Symfony/Component/ValueExporter/Formatter/EntityToStringFormatter.php @@ -39,6 +39,10 @@ public function formatToString($value) { $id = isset($value->id) ? $value->id : (is_callable(array($value, 'id')) ? $value->id() : $value->getId()); + if (method_exists($value, '__toString')) { + return sprintf('entity:%s(%s) "%s"', $id, get_class($value), $value); + } + return sprintf('entity:%s(%s)', $id, get_class($value)); } } diff --git a/src/Symfony/Component/ValueExporter/Tests/Fixtures/EntityImplementingToString.php b/src/Symfony/Component/ValueExporter/Tests/Fixtures/EntityImplementingToString.php new file mode 100644 index 0000000000000..370981ce0f73c --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/Fixtures/EntityImplementingToString.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests\Fixtures; + +/** + * Entity with an id getter. + * + * @author Jules Pietri + */ +class EntityImplementingToString +{ + public $id; + private $name; + + public function __construct($id, $name) + { + $this->id = $id; + $this->name = $name; + } + + public function __toString() + { + return (string) $this->name; + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/Fixtures/ObjectImplementingToString.php b/src/Symfony/Component/ValueExporter/Tests/Fixtures/ObjectImplementingToString.php new file mode 100644 index 0000000000000..9455301fd5c90 --- /dev/null +++ b/src/Symfony/Component/ValueExporter/Tests/Fixtures/ObjectImplementingToString.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ValueExporter\Tests\Fixtures; + +/** + * Entity with an id getter. + * + * @author Jules Pietri + */ +class ObjectImplementingToString +{ + private $name; + + public function __construct($name) + { + $this->name = $name; + } + + public function __toString() + { + return (string) $this->name; + } +} diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index 831ee4e9001ae..1ffa0274400b4 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -13,6 +13,8 @@ use Symfony\Component\ValueExporter\Formatter\TraversableToStringFormatter; use Symfony\Component\ValueExporter\Tests\Fixtures\Entity; +use Symfony\Component\ValueExporter\Tests\Fixtures\EntityImplementingToString; +use Symfony\Component\ValueExporter\Tests\Fixtures\ObjectImplementingToString; use Symfony\Component\ValueExporter\Tests\Fixtures\PublicEntity; use Symfony\Component\ValueExporter\Tests\Fixtures\TraversableInstance; use Symfony\Component\ValueExporter\ValueExporter; @@ -87,6 +89,10 @@ public function valueProvider() array(0 => 0, '1' => 'un', 'key' => 4.5), 'array(0 => (int) 0, 1 => "un", \'key\' => (float) 4.5)', ), + 'object implementing to string' => array( + new ObjectImplementingToString('test'), + 'object(Symfony\Component\ValueExporter\Tests\Fixtures\ObjectImplementingToString) "test"', + ), 'closure' => array(function() {}, 'object(Closure)'), 'callable string' => array('strlen', '(function) "strlen"'), 'callable array' => array( @@ -105,6 +111,10 @@ public function valueProvider() 'php incomplete class' => array($foo, '__PHP_Incomplete_Class(AppBundle/Foo)'), 'entity' => array(new Entity(23), 'entity:23(Symfony\Component\ValueExporter\Tests\Fixtures\Entity)'), 'public entity' => array(new PublicEntity(23), 'entity:23(Symfony\Component\ValueExporter\Tests\Fixtures\PublicEntity)'), + 'entity implementing to string' => array( + new EntityImplementingToString(23, 'test'), + 'entity:23(Symfony\Component\ValueExporter\Tests\Fixtures\EntityImplementingToString) "test"', + ), ); } From ab119f088ef9d8f8a9465768fe8c6b9c937be427 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 23 Apr 2016 08:34:55 +0200 Subject: [PATCH 11/12] [ValueExporter] tweaked CallableToStringFormatter --- .../ValueExporter/Formatter/CallableToStringFormatter.php | 6 +++++- .../Component/ValueExporter/Tests/ValueExporterTest.php | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php b/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php index 075d2b8d77a1a..8240919bf01eb 100644 --- a/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php +++ b/src/Symfony/Component/ValueExporter/Formatter/CallableToStringFormatter.php @@ -36,7 +36,7 @@ public function formatToString($value) } $caller = is_object($value) ? get_class($value) : (is_object($value[0]) ? get_class($value[0]) : $value[0]); - if (is_object($value)) { + if (is_object($value) || (is_object($value[0]) && isset($value[1]) && '__invoke' === $value[1])) { return sprintf('(invokable) "%s"', $caller); } @@ -45,6 +45,10 @@ public function formatToString($value) $method = substr($method, $cut); } + if ((new \ReflectionMethod($caller, $method))->isStatic()) { + return sprintf('(static) "%s::%s"', $caller, $method); + } + return sprintf('(callable) "%s::%s"', $caller, $method); } } diff --git a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php index 1ffa0274400b4..ec544c6000112 100644 --- a/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php +++ b/src/Symfony/Component/ValueExporter/Tests/ValueExporterTest.php @@ -45,7 +45,7 @@ public function testExportValueExpanded() $exportedValue = << (callable) "Symfony\Component\ValueExporter\ValueExporter::export" + 0 => (static) "Symfony\Component\ValueExporter\ValueExporter::export" ) EOT; @@ -100,6 +100,7 @@ public function valueProvider() '(callable) "Symfony\Component\ValueExporter\Tests\ValueExporterTest::testExportValue"', ), 'invokable object' => array($this, '(invokable) "Symfony\Component\ValueExporter\Tests\ValueExporterTest"'), + 'invokable object as array' => array(array($this, '__invoke'), '(invokable) "Symfony\Component\ValueExporter\Tests\ValueExporterTest"'), 'datetime' => array( new \DateTime('2014-06-10 07:35:40', new \DateTimeZone('UTC')), 'object(DateTime) - 2014-06-10T07:35:40+0000', From 826e8fb5bdd5fda0298f7fdc66011778631bf748 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sat, 23 Apr 2016 09:15:44 +0200 Subject: [PATCH 12/12] [ValueExporter] fixed some doc blocks in AbstractValueExporter --- .../ValueExporter/Exporter/AbstractValueExporter.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php index f7ee40e18295e..11c0bffef0da4 100644 --- a/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php +++ b/src/Symfony/Component/ValueExporter/Exporter/AbstractValueExporter.php @@ -39,9 +39,9 @@ abstract class AbstractValueExporter implements ValueExporterInterface protected $formatterInterface = FormatterInterface::class; /** - * An array of priorities by formatter class. + * An array indexed by formatter FQCN with a corresponding priority as value. * - * @var array[] + * @var int[] */ private $formatters = array(); @@ -53,16 +53,18 @@ abstract class AbstractValueExporter implements ValueExporterInterface private $sortedFormatters; /** - * An array of cached formatters instances by class. + * An array of cached formatters instances by their FQCN. * * @var FormatterInterface[] */ private $cachedFormatters = array(); /** - * Takes {@link FormatterInterface} as arguments. + * Takes {@link FormatterInterface} FQCN as arguments. * * They will be called in the given order. + * Alternatively, instead of a class, you can pass an array with + * a class and its priority {@see self::addFormatters}. */ final public function __construct() { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy