Pular para o conteúdo principal

Formatters

Formatters are responsible for converting array data into various output formats like JSON, XML, YAML, CSV, and plain text. All formatters implement the FormatterInterface and can be used directly or through the Serialize class.

Overview​

The PHP Serializer library provides several built-in formatters:

  • JsonFormatter - Converts data to JSON format
  • XmlFormatter - Converts data to XML format with customization options
  • YamlFormatter - Converts data to YAML format
  • CsvFormatter - Converts data to CSV format
  • PlainTextFormatter - Converts data to plain text with customization options

Using Formatters​

Direct Usage​

You can use formatters directly by instantiating them and calling the process() method:

use ByJG\Serializer\Formatter\JsonFormatter;
use ByJG\Serializer\Formatter\XmlFormatter;

$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'age' => 30
];

// Direct formatter usage
echo (new JsonFormatter())->process($data);
echo (new XmlFormatter())->process($data);

Through Serialize Class​

Alternatively, use the Serialize class for a more convenient API:

use ByJG\Serializer\Serialize;

$result = Serialize::from($data)->toJson();
$result = Serialize::from($data)->toXml();
$result = Serialize::from($data)->toYaml();
$result = Serialize::from($data)->toCsv();
$result = Serialize::from($data)->toPlainText();

Built-in Formatters​

JsonFormatter​

The simplest formatter that converts data to JSON format using PHP's native json_encode().

use ByJG\Serializer\Formatter\JsonFormatter;

$formatter = new JsonFormatter();
echo $formatter->process($data);

// Output:
// {"name":"John Doe","email":"[email protected]","age":30}

Features:

  • No configuration options
  • Uses PHP's json_encode() with default settings
  • Handles both arrays and objects

XmlFormatter​

Converts data to XML format with extensive customization options.

Basic Usage​

use ByJG\Serializer\Formatter\XmlFormatter;

$data = [
'name' => 'John Doe',
'email' => '[email protected]'
];

$formatter = new XmlFormatter();
echo $formatter->process($data);

// Output:
// <?xml version="1.0"?>
// <root>
// <name>John Doe</name>
// <email>[email protected]</email>
// </root>

Configuration Methods​

1. withRootElement(string $rootElement): XmlFormatter

Customizes the XML root element name (default: "root").

$xml = (new XmlFormatter())
->withRootElement("user")
->process($data);

// Output:
// <?xml version="1.0"?>
// <user>
// <name>John Doe</name>
// <email>[email protected]</email>
// </user>

2. withListElement(string $listElement): XmlFormatter

Customizes the element name for array items (default: "item").

$users = [
['name' => 'John', 'age' => 30],
['name' => 'Jane', 'age' => 25]
];

$xml = (new XmlFormatter())
->withRootElement("users")
->withListElement("user")
->process($users);

// Output:
// <?xml version="1.0"?>
// <users>
// <user>
// <name>John</name>
// <age>30</age>
// </user>
// <user>
// <name>Jane</name>
// <age>25</age>
// </user>
// </users>

3. withListElementSuffix(): XmlFormatter

Adds numeric suffixes to list element names for better identification.

$xml = (new XmlFormatter())
->withRootElement("users")
->withListElement("user")
->withListElementSuffix() // Enables numeric suffixes
->process($users);

// Output:
// <?xml version="1.0"?>
// <users>
// <user0>
// <name>John</name>
// <age>30</age>
// </user0>
// <user1>
// <name>Jane</name>
// <age>25</age>
// </user1>
// </users>

Complete Example​

$products = [
['id' => 1, 'name' => 'Laptop', 'price' => 999],
['id' => 2, 'name' => 'Mouse', 'price' => 25]
];

$xml = (new XmlFormatter())
->withRootElement("catalog")
->withListElement("product")
->withListElementSuffix()
->process($products);

YamlFormatter​

Converts data to YAML format using the Symfony YAML component.

use ByJG\Serializer\Formatter\YamlFormatter;

$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'roles' => ['admin', 'user']
];

$formatter = new YamlFormatter();
echo $formatter->process($data);

// Output:
// name: John Doe
// roles:
// - admin
// - user

Features:

  • No configuration options
  • Uses Symfony YAML component
  • Handles nested arrays and objects elegantly

CsvFormatter​

Converts data to CSV (Comma-Separated Values) format.

Basic Usage​

use ByJG\Serializer\Formatter\CsvFormatter;

$users = [
['name' => 'John Doe', 'email' => '[email protected]', 'age' => 30],
['name' => 'Jane Smith', 'email' => '[email protected]', 'age' => 25]
];

$formatter = new CsvFormatter();
echo $formatter->process($users);

// Output:
// name,email,age
// "John Doe",[email protected],30
// "Jane Smith",[email protected],25

Behavior​

  • Headers: Automatically generates headers from the keys of the first array element
  • Single Arrays: If you pass a single associative array, it's automatically wrapped in an array
  • Empty Arrays: Returns an empty string
  • Escape Character: Uses backslash (\\) as the escape character
  • Multidimensional Support: Handles arrays of arrays; nested objects are not supported

Example with Single Object​

$user = ['name' => 'John', 'email' => '[email protected]'];

echo (new CsvFormatter())->process($user);

// Output:
// name,email

PlainTextFormatter​

Converts data to plain text format with extensive customization options.

Basic Usage​

use ByJG\Serializer\Formatter\PlainTextFormatter;

$data = [
'name' => 'John Doe',
'email' => '[email protected]',
'age' => 30
];

$formatter = new PlainTextFormatter();
echo $formatter->process($data);

// Output:
// John Doe
// 30

Configuration Methods​

1. withBreakLine(string $breakLine): PlainTextFormatter

Customizes the line break character/string (default: "\n").

$text = (new PlainTextFormatter())
->withBreakLine(" | ")
->process($data);

// Output: John Doe | [email protected] | 30 |

2. withStartOfLine(string $startOfLine): PlainTextFormatter

Adds a prefix to the start of each line (default: "").

$text = (new PlainTextFormatter())
->withStartOfLine("- ")
->process($data);

// Output:
// - John Doe
// - 30

3. withIgnorePropertyName(bool $ignorePropertyName): PlainTextFormatter

Controls whether property names are included in the output (default: true).

$text = (new PlainTextFormatter())
->withIgnorePropertyName(false) // Include property names
->process($data);

// Output:
// name=John Doe
// age=30

HTML List Example​

Create an HTML list using PlainTextFormatter:

$data = ['Apple', 'Banana', 'Orange'];

$html = (new PlainTextFormatter())
->withStartOfLine("<li>")
->withBreakLine("</li>\n")
->process($data);

echo "<ul>\n" . $html . "</ul>";

// Output:
// <ul>
// <li>Apple</li>
// <li>Banana</li>
// <li>Orange</li>
// </ul>

Complete Example​

$products = [
'Laptop' => 999,
'Mouse' => 25,
'Keyboard' => 75
];

$text = (new PlainTextFormatter())
->withIgnorePropertyName(false)
->withStartOfLine("* ")
->withBreakLine("\n")
->process($products);

// Output:
// * Laptop=999
// * Mouse=25
// * Keyboard=75

FormatterInterface​

All formatters implement the FormatterInterface, which defines a single method:

namespace ByJG\Serializer\Formatter;

interface FormatterInterface
{
/**
* Process the serializable data and return formatted output
*
* @param array|object $serializable The data to format
* @return string|bool The formatted output
*/
public function process(array|object $serializable): string|bool;
}

Creating Custom Formatters​

You can create custom formatters by implementing the FormatterInterface:

Example: HTML Table Formatter​

namespace MyApp\Formatters;

use ByJG\Serializer\Formatter\FormatterInterface;
use ByJG\Serializer\Serialize;

class HtmlTableFormatter implements FormatterInterface
{
private bool $includeHeaders = true;
private string $tableClass = '';

public function withTableClass(string $class): self
{
$this->tableClass = $class;
return $this;
}

public function withoutHeaders(): self
{
$this->includeHeaders = false;
return $this;
}

public function process(array|object $serializable): string|bool
{
// Convert object to array if needed
if (is_object($serializable)) {
$serializable = Serialize::from($serializable)->toArray();
}

// Ensure we have an array of arrays
if (empty($serializable)) {
return '<table></table>';
}

$isMulti = is_array(reset($serializable));
if (!$isMulti) {
$serializable = [$serializable];
}

// Start table
$class = $this->tableClass ? " class=\"{$this->tableClass}\"" : '';
$html = "<table{$class}>\n";

// Add headers
if ($this->includeHeaders) {
$headers = array_keys(reset($serializable));
$html .= " <thead>\n <tr>\n";
foreach ($headers as $header) {
$html .= " <th>" . htmlspecialchars($header) . "</th>\n";
}
$html .= " </tr>\n </thead>\n";
}

// Add rows
$html .= " <tbody>\n";
foreach ($serializable as $row) {
$html .= " <tr>\n";
foreach ($row as $value) {
$html .= " <td>" . htmlspecialchars($value) . "</td>\n";
}
$html .= " </tr>\n";
}
$html .= " </tbody>\n</table>";

return $html;
}
}

Using the Custom Formatter​

use MyApp\Formatters\HtmlTableFormatter;

$users = [
['name' => 'John Doe', 'email' => '[email protected]'],
['name' => 'Jane Smith', 'email' => '[email protected]']
];

$html = (new HtmlTableFormatter())
->withTableClass('table table-striped')
->process($users);

echo $html;

Example: Markdown Formatter​

namespace MyApp\Formatters;

use ByJG\Serializer\Formatter\FormatterInterface;
use ByJG\Serializer\Serialize;

class MarkdownFormatter implements FormatterInterface
{
public function process(array|object $serializable): string|bool
{
if (is_object($serializable)) {
$serializable = Serialize::from($serializable)->toArray();
}

if (empty($serializable)) {
return '';
}

// Check if it's a list of objects
$isMulti = is_array(reset($serializable));
if (!$isMulti) {
// Single object - format as key-value pairs
$markdown = '';
foreach ($serializable as $key => $value) {
$markdown .= "**{$key}**: {$value}\n\n";
}
return $markdown;
}

// Multiple objects - format as table
$headers = array_keys(reset($serializable));

// Create header row
$markdown = '| ' . implode(' | ', $headers) . " |\n";

// Create separator
$markdown .= '| ' . implode(' | ', array_fill(0, count($headers), '---')) . " |\n";

// Create data rows
foreach ($serializable as $row) {
$markdown .= '| ' . implode(' | ', array_values($row)) . " |\n";
}

return $markdown;
}
}

Using the Markdown Formatter​

use MyApp\Formatters\MarkdownFormatter;

$users = [
['name' => 'John Doe', 'role' => 'Admin'],
['name' => 'Jane Smith', 'role' => 'User']
];

echo (new MarkdownFormatter())->process($users);

// Output:
// | name | role |
// | --- | --- |
// | John Doe | Admin |
// | Jane Smith | User |

Best Practices​

1. Choose the Right Formatter​

  • JsonFormatter: API responses, data storage, JavaScript integration
  • XmlFormatter: Legacy systems, SOAP services, RSS feeds
  • YamlFormatter: Configuration files, human-readable data
  • CsvFormatter: Data exports, spreadsheet compatibility
  • PlainTextFormatter: Log files, simple displays, custom text formats

2. Use Configuration Methods​

Take advantage of formatter configuration methods to customize output:

// Good - customized for your use case
$xml = (new XmlFormatter())
->withRootElement("products")
->withListElement("product")
->process($data);

// Less ideal - generic root element
$xml = (new XmlFormatter())->process($data);

3. Method Chaining​

All configuration methods support fluent interfaces:

$text = (new PlainTextFormatter())
->withBreakLine("\n")
->withStartOfLine("* ")
->withIgnorePropertyName(false)
->process($data);

4. Combine with Serialize Modifiers​

Use Serialize modifiers before formatting:

$json = Serialize::from($user)
->withIgnoreProperties(['password', 'secret'])
->withDoNotParseNullValues()
->toJson();

5. Custom Formatters​

When built-in formatters don't meet your needs:

  • Implement FormatterInterface
  • Support method chaining with configuration
  • Handle both arrays and objects
  • Consider edge cases (empty data, nested structures)

Performance Considerations​

Caching​

Formatters don't cache results. If you're formatting the same data multiple times, cache the output:

// Bad - formats twice
$json1 = (new JsonFormatter())->process($data);
$json2 = (new JsonFormatter())->process($data);

// Good - format once, reuse
$json = (new JsonFormatter())->process($data);
$result1 = $json;
$result2 = $json;

Large Datasets​

For large datasets, consider:

  • CSV: Most efficient for tabular data
  • JSON: Good balance of speed and features
  • XML: Can be verbose and slower for large datasets

Memory Usage​

Formatters process data in memory. For very large datasets:

  • Use streaming APIs if available
  • Process data in chunks
  • Consider database exports instead of in-memory formatting
  • Serialize - Main serialization class that uses formatters
  • ObjectCopy - Copy data between objects before formatting
  • BaseModel - Model base class with toArray() for formatting