Limitations
Known limitations of PHP Toml.
Integer Range
Integers are parsed using PHP's native int type. Values exceeding PHP_INT_MAX (typically 9223372036854775807 on 64-bit systems) will be clamped silently.
# May be clamped on some systems
big_number = 9999999999999999999Workaround: If you need arbitrary precision integers, post-process the AST or parsed values with GMP:
$document = Toml::parse($input);
// Find integer nodes and convert with gmp_init()DateTime Precision
PHP's DateTimeImmutable supports microsecond precision (6 digits). Nanosecond values (9 digits) are truncated:
# Full precision
precise = 2024-01-15T10:30:00.123456Z
# Truncated to microseconds
nano = 2024-01-15T10:30:00.123456789Z
# Becomes: 2024-01-15T10:30:00.123456ZComment Preservation
Comments can be preserved by encodeDocument() when the AST was parsed with trivia enabled:
# This comment can be preserved
key = "value" # This tooExample:
$document = Toml::parse($input, true);
$toml = Toml::encodeDocument(
$document,
new EncoderOptions(documentFormatting: DocumentFormattingMode::SourceAware),
);Plain encode() still emits normalized TOML and does not preserve source comments.
Formatting Preservation
Formatting preservation is strongest when re-encoding a trivia-preserving AST in DocumentFormattingMode::SourceAware.
Unchanged parsed regions can round-trip losslessly. Edited regions keep local formatting where the AST carries consistent evidence and otherwise fall back to canonical local formatting.
# Original multiline array
values = [
1,
2,
]
# After adding item 3 - multiline format preserved
values = [
1,
2,
3,
]For the exact source-aware editing contract, see Compatibility.
Local DateTime Types
Local datetime types (LocalDateTime, LocalDate, LocalTime) are returned as strings, not DateTimeImmutable:
$config = Toml::decode('date = 1979-05-27');
// $config['date'] is string "1979-05-27", not DateTimeImmutableThis is because local dates have no timezone information, making DateTimeImmutable semantically incorrect.
Workaround:
$date = DateTimeImmutable::createFromFormat('Y-m-d', $config['date']);For encoding local temporal TOML literals, use explicit wrappers:
use PhpCollective\Toml\Value\LocalDate;
$toml = Toml::encode([
'date' => new LocalDate('2024-03-15'),
]);Null Values
TOML has no null type. By default, PHP null values throw EncodeException during encoding:
Toml::encode([
'present' => 'value',
'missing' => null,
]); // Throws EncodeExceptionWorkaround: Use the skipNulls option to silently omit null values:
use PhpCollective\Toml\Encoder\EncoderOptions;
$toml = Toml::encode([
'present' => 'value',
'missing' => null,
], new EncoderOptions(skipNulls: true));
// Output: present = "value"This also works for nulls in arrays and inline tables.
Object Encoding
Only DateTimeInterface objects and explicit TOML value wrappers are supported for direct object encoding. Other objects must be converted to arrays:
// This throws EncodeException
Toml::encode(['obj' => new MyClass()]);
// Convert to array first
Toml::encode(['obj' => (array)$myObject]);Recursive Structures
Circular references throw EncodeException:
$a = ['key' => 'value'];
$a['self'] = &$a; // Circular reference
Toml::encode($a); // Throws EncodeExceptionControl Characters
The TOML spec forbids unescaped control characters (U+0000 to U+001F, except tab U+0009) in basic strings and comments. Currently, the parser accepts these characters without validation for performance reasons.
# Per TOML spec, this should be rejected:
invalid = "hello^Aworld" # ^A = 0x01
# The parser currently accepts it (lenient behavior)A future version may add strict control character validation.
Maximum Nesting
While there's no explicit limit, deeply nested structures may cause stack issues:
[a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z]
key = "very deep"Future Improvements
The largest remaining improvement areas are:
- Optional GMP-backed handling for very large integers
- Streaming or incremental parsing for very large files