This is a parser/printer for a subset of PHP focused on data. (It serves a role similar to a full-service YAML library - except with *.php
data-files.) Key features:
- Allows
array
values andscalar
values (string
,int
,bool
, etc). - Allows comments for the overall document and for individual items in the tree.
- Allows tagged-values (a.k.a. factory-functions) which look like global or static method-calls.
- Allows deferred construction (
fn() => [...data...]
) - Prohibits objects, loops, math, concatenation, includes, custom functions, etc.
A basic document looks like this:
<?php
return [
// First item is a string.
'key_1' => 'value_1',
// Second item is an array of floats.
'key_2' => [2.1, 2.2, 2.3],
// Third item is an array.
'key_3' => [
'part_a' => 'Apple',
'part_b' => 'Banana',
]
];
This next example is similar, but it adds a "tagged value" or "factory function" called MyHelper::translate()
:
<?php
use MyHelper as H;
return [
'id' => 1234,
'name' => 'greeter',
'label' => H::translate('Hello World'),
];
Note that H::translate('Hello world')
takes exactly one parameter. It only supports a subset of PHP function-calls -- i.e. with one parameter; with global-function or static-method. (H::translate
is less like an open-ended function-call and more like a tag that describes Hello world
.)
The same concept can be applied to generate objects/records, as long as there is exactly one parameter:
use MyHelper as H;
return H::record([
'id' => 1234,
'name' => 'greeter',
'label' => H::translate('Hello World'),
]);
Value resolution may be defererd, as in:
use MyHelper as H;
return H::record([
'id' => 1234,
'name' => 'greeter',
'label' => fn() => H::translate('Hello World'),
]);
Generate a new *.php
data file. Populate it with importData($array)
:
$doc = PhpArrayDocument::create();
$doc->getRoot()->importData([
'id' => 1234,
'name' => 'greeting',
'label' => ScalarNode::create('Hello World')->setFactory('E::ts'),
]);
$file = 'my.data.php';
file_put_contents($file, (new Printer())->print($doc));
Read an existing file. Update individual items in the parse-tree. Save the updated file.
$file = 'my.data.php';
$doc = (new Parser())->parse(file_get_contents($file));
$root = $doc->getRoot();
$root['id'] = ScalarNode::create(100);
$root['name'] = ScalarNode::create('greeting');
$root['label'] = ScalarNode::create('Hello World')->setFactory('E::ts');
file_put_contents($file, (new Printer())->print($doc));
Update an existing file. Do a global search (walkNodes()
). Find references to OldHelper::method
and replace them with NewHelper::method
.
$file = 'my.data.php';
$doc = (new Parser())->parse(file_get_contents($file));
foreach ($doc->getRoot()->walkNodes() as $node) {
if ($node->getFactory() === 'OldHelper::method') {
$node->setFactory('NewHelper::method');
}
}
file_put_contents($file, (new Printer())->print($doc));
Some commands to help with debugging:
## Parse and re-print an improvised PHP snippet
echo '<?php return [1,2,3];' | ./scripts/reprint.php
## Tokenize an improvised PHP snippet
echo '<?php return [1,2,3];' | ./scripts/tokenize.php
## Parse an improvised PHP snippet
echo '<?php return [1,2,3];' | ./scripts/parse.php
## Parse and re-print a PHP file
cat examples/simple-array-7.4.php | ./scripts/reprint.php | less
## Tokenize a PHP file
cat examples/simple-array-7.4.php | ./scripts/tokenize.php | less
## Parse a PHP file
cat examples/simple-array-7.4.php | ./scripts/parse.php | less
- Basic Concepts
- Substance: Each "PHP array document" contains a tree of
array
s andscalar
s. - Metadata: Individual values may be annotated with comments and/or factory-functions (such as
ts(...)
). - Evaluation: If you
include
orrequire
the PHP document directly, you will literally getarray
s andscalar
s. - Read/Write: If you need to programmatically inspect or update the content, then the
PhpArrayDocument
aims to help.
- Substance: Each "PHP array document" contains a tree of
- Verbs
- Parse: Read the PHP document as an instance of
PhpArrayDocument
- Print: Render
PhpArrayDocument
as a string (<?php return [...]
) - Import Data: Add basic PHP array data to a
PhpArrayDocument
(without any metadata/comments/factory-functions) - Export Data: Grab the PHP (discarding any metadata/comments/factory-functions)
- Walk Nodes: Visit all the nodes in the tree. Useful for general filtering/searching/replacing.
- Parse: Read the PHP document as an instance of
- Classes
- Data-Focused Classes
PhpArrayDocument
: This captures the overall*.php
file, including any top-level elements (use
or docblocks) and the rootarray
.ArrayNode
(extendsBaseNode
): An element in the tree that corresponds toarray()
ArrayItemNode
(extendsBaseNode
): A key-value pair that exists within anarray()
ScalarNode
(extendsBaseNode
): An atomic value that lives inside an array.
- Functionality-Focused Classes
Parser
: Take a rawstring
. Generate aPhpArrayDocument
.Printer
: Take aPhpArrayDocument
. Generate a string
- Data-Focused Classes