Skip to main content

ReactJS in PHP: Writing Compilers Is Easy and Fun! Best Php Training Trivandrum

ReactJS in PHP: Writing Compilers Is Easy and Fun!


Abstract image of blocks coming together

Creating Compilers

Generating Tokens

function tokens($code) {
    $tokens = [];

    $length = strlen($code);
    $cursor = 0;

    while ($cursor < $length) {
        if ($code[$cursor] === "{") {
            print "ATTRIBUTE STARTED ({$cursor})" . PHP_EOL;
        }

        if ($code[$cursor] === "}") {
            print "ATTRIBUTE ENDED ({$cursor})" . PHP_EOL;
        }

        if ($code[$cursor] === "<") {
            print "ELEMENT STARTED ({$cursor})" . PHP_EOL;
        }

        if ($code[$cursor] === ">") {
            print "ELEMENT ENDED ({$cursor})" . PHP_EOL;
        }

        $cursor++;
    }
}

$code = '
    <?php

    $classNames = "foo bar";
    $message = "hello world";

    $thing = (
        <div
            className={() => { return "outer-div"; }}
            nested={<span className={"nested-span"}>with text</span>}
        >
            a bit of text before
            <span>
                {$message} with a bit of extra text
            </span>
            a bit of text after
        </div>
    );
';

tokens($code);

// ELEMENT STARTED (5)
// ELEMENT STARTED (95)
// ATTRIBUTE STARTED (122)
// ELEMENT ENDED (127)
// ATTRIBUTE STARTED (129)
// ATTRIBUTE ENDED (151)
// ATTRIBUTE ENDED (152)
// ATTRIBUTE STARTED (173)
// ELEMENT STARTED (174)
// ATTRIBUTE STARTED (190)
// ATTRIBUTE ENDED (204)
// ELEMENT ENDED (205)
// ELEMENT STARTED (215)
// ELEMENT ENDED (221)
// ATTRIBUTE ENDED (222)
// ELEMENT ENDED (232)
// ELEMENT STARTED (279)
// ELEMENT ENDED (284)
// ATTRIBUTE STARTED (302)
// ATTRIBUTE ENDED (311)
// ELEMENT STARTED (350)
// ELEMENT ENDED (356)
// ELEMENT STARTED (398)
// ELEMENT ENDED (403)
preg_match("#^</?[a-zA-Z]#", substr($code, $cursor, 3), $matchesStart);

if (count($matchesStart)) {
    print "ELEMENT STARTED ({$cursor})" . PHP_EOL;
}

// ...

// ELEMENT STARTED (95)
// ATTRIBUTE STARTED (122)
// ELEMENT ENDED (127)
// ATTRIBUTE STARTED (129)
// ATTRIBUTE ENDED (151)
// ATTRIBUTE ENDED (152)
// ATTRIBUTE STARTED (173)
// ELEMENT STARTED (174)
// ...
preg_match("#^=>#", substr($code, $cursor - 1, 2), $matchesEqualBefore);
preg_match("#^>=#", substr($code, $cursor, 2), $matchesEqualAfter);

if ($code[$cursor] === ">" && !$matchesEqualBefore && !$matchesEqualAfter) {
    print "ELEMENT ENDED ({$cursor})" . PHP_EOL;
}

// ...

// ELEMENT STARTED (95)
// ATTRIBUTE STARTED (122)
// ATTRIBUTE STARTED (129)
// ATTRIBUTE ENDED (151)
// ATTRIBUTE ENDED (152)
// ATTRIBUTE STARTED (173)
// ELEMENT STARTED (174)
// ...
function tokens($code) {
    $tokens = [];

    $length = strlen($code);
    $cursor = 0;

    $elementLevel = 0;
    $elementStarted = null;
    $elementEnded = null;

    $attributes = [];
    $attributeLevel = 0;
    $attributeStarted = null;
    $attributeEnded = null;

    while ($cursor < $length) {
        $extract = trim(substr($code, $cursor, 5)) . "...";

        if ($code[$cursor] === "{" && $elementStarted !== null) {
            if ($attributeLevel === 0) {
                print "ATTRIBUTE STARTED ({$cursor}, {$extract})" . PHP_EOL;
                $attributeStarted = $cursor;
            }

            $attributeLevel++;
        }

        if ($code[$cursor] === "}" && $elementStarted !== null) {
            $attributeLevel--;

            if ($attributeLevel === 0) {
                print "ATTRIBUTE ENDED ({$cursor})" . PHP_EOL;
                $attributeEnded = $cursor;
            }
        }

        preg_match("#^</?[a-zA-Z]#", substr($code, $cursor, 3), $matchesStart);

        if (count($matchesStart) && $attributeLevel < 1) {
            print "ELEMENT STARTED ({$cursor}, {$extract})" . PHP_EOL;

            $elementLevel++;
            $elementStarted = $cursor;
        }

        preg_match("#^=>#", substr($code, $cursor - 1, 2), $matchesEqualBefore);
        preg_match("#^>=#", substr($code, $cursor, 2), $matchesEqualAfter);

        if (
            $code[$cursor] === ">"
            && !$matchesEqualBefore && !$matchesEqualAfter
            && $attributeLevel < 1
        ) {
            print "ELEMENT ENDED ({$cursor})" . PHP_EOL;

            $elementLevel--;
            $elementEnded = $cursor;
        }

        if ($elementStarted && $elementEnded) {
            // TODO

            $elementStarted = null;
            $elementEnded = null;
        }

        $cursor++;
    }
}

// ...

// ELEMENT STARTED (95, <div...)
// ATTRIBUTE STARTED (122, {() =...)
// ATTRIBUTE ENDED (152)
// ATTRIBUTE STARTED (173, {<spa...)
// ATTRIBUTE ENDED (222)
// ELEMENT ENDED (232)
// ELEMENT STARTED (279, <span...)
// ELEMENT ENDED (284)
// ELEMENT STARTED (350, </spa...)
// ELEMENT ENDED (356)
// ELEMENT STARTED (398, </div...)
// ELEMENT ENDED (403)
function tokens($code) {
    $tokens = [];

    $length = strlen($code);
    $cursor = 0;

    $elementLevel = 0;
    $elementStarted = null;
    $elementEnded = null;

    $attributes = [];
    $attributeLevel = 0;
    $attributeStarted = null;
    $attributeEnded = null;

    $carry = 0;

    while ($cursor < $length) {
        if ($code[$cursor] === "{" && $elementStarted !== null) {
            if ($attributeLevel === 0) {
                $attributeStarted = $cursor;
            }

            $attributeLevel++;
        }

        if ($code[$cursor] === "}" && $elementStarted !== null) {
            $attributeLevel--;

            if ($attributeLevel === 0) {
                $attributeEnded = $cursor;
            }
        }

        if ($attributeStarted && $attributeEnded) {
            $position = (string) count($attributes);
            $positionLength = strlen($position);

            $attribute = substr(
                $code, $attributeStarted + 1, $attributeEnded - $attributeStarted - 1
            );

            $attributes[$position] = $attribute;

            $before = substr($code, 0, $attributeStarted + 1);
            $after = substr($code, $attributeEnded);

            $code = $before . $position . $after;

            $cursor = $attributeStarted + $positionLength + 2 /* curlies */;
            $length = strlen($code);

            $attributeStarted = null;
            $attributeEnded = null;

            continue;
        }

        preg_match("#^</?[a-zA-Z]#", substr($code, $cursor, 3), $matchesStart);

        if (count($matchesStart) && $attributeLevel < 1) {
            $elementLevel++;
            $elementStarted = $cursor;
        }

        preg_match("#^=>#", substr($code, $cursor - 1, 2), $matchesEqualBefore);
        preg_match("#^>=#", substr($code, $cursor, 2), $matchesEqualAfter);

        if (
            $code[$cursor] === ">"
            && !$matchesEqualBefore && !$matchesEqualAfter
            && $attributeLevel < 1
        ) {
            $elementLevel--;
            $elementEnded = $cursor;
        }

        if ($elementStarted !== null && $elementEnded !== null) {
            $distance = $elementEnded - $elementStarted;

            $carry += $cursor;

            $before = trim(substr($code, 0, $elementStarted));
            $tag = trim(substr($code, $elementStarted, $distance + 1));
            $after = trim(substr($code, $elementEnded + 1));

            $token = ["tag" => $tag, "started" => $carry];

            if (count($attributes)) {
                $token["attributes"] = $attributes;
            }

            $tokens[] = $before;
            $tokens[] = $token;

            $attributes = [];

            $code = $after;
            $length = strlen($code);
            $cursor = 0;

            $elementStarted = null;
            $elementEnded = null;

            continue;
        }

        $cursor++;
    }

    return $tokens;
}

$code = '
    <?php

    $classNames = "foo bar";
    $message = "hello world";

    $thing = (
        <div
            className={() => { return "outer-div"; }}
            nested={<span className={"nested-span"}>with text</span>}
        >
            a bit of text before
            <span>
                {$message} with a bit of extra text
            </span>
            a bit of text after
        </div>
    );
';

tokens($code);

// Array
// (
//     [0] => <?php
//
//     $classNames = "foo bar";
//     $message = "hello world";
//
//     $thing = (
//     [1] => Array
//         (
//             [tag] => <div className={0} nested={1}>
//             [started] => 157
//             [attributes] => Array
//                 (
//                     [0] => () => { return "outer-div"; }
//                     [1] => <span className={"nested-span"}>with text</span>
//                 )
//
//         )
//
//     [2] => a bit of text before
//     [3] => Array
//         (
//             [tag] => <span>
//             [started] => 195
//         )
//
//     [4] => {$message} with a bit of extra text
//     [5] => Array
//         (
//             [tag] => </span>
//             [started] => 249
//         )
//
//     [6] => a bit of text after
//     [7] => Array
//         (
//             [tag] => </div>
//             [started] => 282
//         )
//
// )
function tokens($code) {
    // ...

    while ($cursor < $length) {
        // ...

        if ($elementStarted !== null && $elementEnded !== null) {
            // ...

            foreach ($attributes as $key => $value) {
                $attributes[$key] = tokens($value);
            }

            if (count($attributes)) {
                $token["attributes"] = $attributes;
            }

            // ...
        }

        $cursor++;
    }

    $tokens[] = trim($code);

    return $tokens;
}

// ...

// Array
// (
//     [0] => <?php
//
//     $classNames = "foo bar";
//     $message = "hello world";
//
//     $thing = (
//     [1] => Array
//         (
//             [tag] => <div className={0} nested={1}>
//             [started] => 157
//             [attributes] => Array
//                 (
//                     [0] => Array
//                         (
//                             [0] => () => { return "outer-div"; }
//                         )
//
//                     [1] => Array
//                         (
//                             [1] => Array
//                                 (
//                                     [tag] => <span className={0}>
//                                     [started] => 19
//                                     [attributes] => Array
//                                         (
//                                             [0] => Array
//                                                 (
//                                                     [0] => "nested-span"
//                                                 )
//
//                                         )
//
//                                 )
//
//                            [2] => with text
//                            [3] => Array
//                                (
//                                    [tag] => </span>
//                                    [started] => 34
//                                )
//                         )
//
//                 )
//
//         )
//
// ...

Organizing Tokens

function nodes($tokens) {
    $cursor = 0;
    $length = count($tokens);

    while ($cursor < $length) {
        $token = $tokens[$cursor];

        if (is_array($token)) {
            print $token["tag"] . PHP_EOL;
        }

        $cursor++;
    }
}

$tokens = [
    0 => '<?php

    $classNames = "foo bar";
    $message = "hello world";

    $thing = (',
    1 => [
        'tag' => '<div className={0} nested={1}>',
        'started' => 157,
        'attributes' => [
            0 => [
                0 => '() => { return "outer-div"; }',
            ],
            1 => [
                1 => [
                    'tag' => '<span className={0}>',
                    'started' => 19,
                    'attributes' => [
                        0 => [
                            0 => '"nested-span"',
                        ],
                    ],
                ],
                2 => 'with text</span>',
            ],
        ],
    ],
    2 => 'a bit of text before',
    3 => [
        'tag' => '<span>',
        'started' => 195,
    ],
    4 => '{$message} with a bit of extra text',
    5 => [
        'tag' => '</span>',
        'started' => 249,
    ],
    6 => 'a bit of text after',
    7 => [
        'tag' => '</div>',
        'started' => 282,
    ],
    8 => ');',
];

nodes($tokens);

// <div className={0} nested={1}>
// <span>
// </span>
// </div>
function nodes($tokens) {
    $cursor = 0;
    $length = count($tokens);

    while ($cursor < $length) {
        $token = $tokens[$cursor];

        if (is_array($token) && $token["tag"][1] !== "/") {
            preg_match("#^<([a-zA-Z]+)#", $token["tag"], $matches);

            print "OPENING {$matches[1]}" . PHP_EOL;
        }

        if (is_array($token) && $token["tag"][1] === "/") {
            preg_match("#^</([a-zA-Z]+)#", $token["tag"], $matches);

            print "CLOSING {$matches[1]}" . PHP_EOL;
        }

        $cursor++;
    }

    return $tokens;
}

// ...

// OPENING div
// OPENING span
// CLOSING span
// CLOSING div
function nodes($tokens) {
    $nodes = [];
    $current = null;

    $cursor = 0;
    $length = count($tokens);

    while ($cursor < $length) {
        $token =& $tokens[$cursor];

        if (is_array($token) && $token["tag"][1] !== "/") {
            preg_match("#^<([a-zA-Z]+)#", $token["tag"], $matches);

            if ($current !== null) {
                $token["parent"] =& $current;
                $current["children"][] =& $token;
            } else {
                $token["parent"] = null;
                $nodes[] =& $token;
            }

            $current =& $token;
            $current["name"] = $matches[1];
            $current["children"] = [];

            if (isset($current["attributes"])) {
                foreach ($current["attributes"] as $key => $value) {
                    $current["attributes"][$key] = nodes($value);
                }

                $current["attributes"] = array_map(function($item) {

                    foreach ($item as $value) {
                        if (isset($value["tag"])) {
                            return $value;
                        }
                    }

                    foreach ($item as $value) {
                        if (!empty($value["token"])) {
                            return $value;
                        }
                    }

                    return null;

                }, $current["attributes"]);
            }
        }

        else if (is_array($token) && $token["tag"][1] === "/") {
            preg_match("#^</([a-zA-Z]+)#", $token["tag"], $matches);

            if ($current === null) {
                throw new Exception("no open tag");
            }

            if ($matches[1] !== $current["name"]) {
                throw new Exception("no matching open tag");
            }

            if ($current !== null) {
                $current =& $current["parent"];
            }
        }

        else if ($current !== null) {
            array_push($current["children"], [
                "parent" => &$current,
                "token" => &$token,
            ]);
        }

        else {
            array_push($nodes, [
                "token" => $token,
            ]);
        }

        $cursor++;
    }

    return $nodes;
}

// ...

// Array
// (
//     [0] => Array
//         (
//             [token] => <?php
//
//     $classNames = "foo bar";
//     $message = "hello world";
//
//     $thing = (
//         )
//
//     [1] => Array
//         (
//             [tag] => <div className={0} nested={1}>
//             [started] => 157
//             [attributes] => Array
//                 (
//                     [0] => Array
//                         (
//                             [token] => () => { return "outer-div"; }
//                         )
//
//                     [1] => Array
//                         (
//                             [tag] => <span className={0}>
//                             [started] => 19
//                             [attributes] => Array
//                                 (
//                                     [0] => Array
//                                         (
//                                             [token] => "nested-span"
//                                         )
//
//                                 )
//
//                             [parent] =>
//                             [name] => span
//                             [children] => Array
//                                 (
//                                     [0] => Array
//                                         (
//                                             [parent] => *RECURSION*
//                                             [token] => with text
//                                         )
//
//                                 )
//
//                         )
//
//                 )
//
//             [parent] =>
//             [name] => div
//             [children] => Array
//                 (
//                     [0] => Array
//                         (
//                             [parent] => *RECURSION*
//                             [token] => a bit of text before
//                         )
//
//                     [1] => Array
//                         (
//                             [tag] => <span>
//                             [started] => 195
//                             [parent] => *RECURSION*
//                             [name] => span
//                             [children] => Array
//                                 (
//                                     [0] => Array
//                                         (
//                                             [parent] => *RECURSION*
//                                             [token] => {$message} with ...
//                                         )
//
//                                 )
//
//                         )
//
//                     [2] => Array
//                         (
//                             [parent] => *RECURSION*
//                             [token] => a bit of text after
//                         )
//
//                 )
//
//         )
//
//     [2] => Array
//         (
//             [token] => );
//         )
//
// )

Rewriting Code

function parse($nodes) {
    $code = "";

    foreach ($nodes as $node) {
        if (isset($node["token"])) {
            $code .= $node["token"] . PHP_EOL;
        }
    }

    return $code;
}

$nodes = [
    0 => [
        'token' => '<?php

        $classNames = "foo bar";
        $message = "hello world";

        $thing = (',
    ],
    1 => [
        'tag' => '<div className={0} nested={1}>',
        'started' => 157,
        'attributes' => [
            0 => [
                'token' => '() => { return "outer-div"; }',
            ],
            1 => [
                'tag' => '<span className={0}>',
                'started' => 19,
                'attributes' => [
                    0 => [
                        'token' => '"nested-span"',
                    ],
                ],
                'name' => 'span',
                'children' => [
                    0 => [
                        'token' => 'with text',
                    ],
                ],
            ],
        ],
        'name' => 'div',
        'children' => [
            0 => [
                'token' => 'a bit of text before',
            ],
            1 => [
                'tag' => '<span>',
                'started' => 195,
                'name' => 'span',
                'children' => [
                    0 => [
                        'token' => '{$message} with a bit of extra text',
                    ],
                ],
            ],
            2 => [
                'token' => 'a bit of text after',
            ],
        ],
    ],
    2 => [
        'token' => ');',
    ],
];

parse($nodes);

// <?php
//
// $classNames = "foo bar";
// $message = "hello world";
//
// $thing = (
// );
require __DIR__ . "/vendor/autoload.php";

function parse($nodes) {
    $code = "";

    foreach ($nodes as $node) {
        if (isset($node["token"])) {
            $code .= $node["token"] . PHP_EOL;
        }

        if (isset($node["tag"])) {
            $props = [];
            $attributes = [];
            $elements = [];

            if (isset($node["attributes"])) {
                foreach ($node["attributes"] as $key => $value) {
                    if (isset($value["token"])) {
                        $attributes["attr_{$key}"] = $value["token"];
                    }

                    if (isset($value["tag"])) {
                        $elements[$key] = true;
                        $attributes["attr_{$key}"] = parse([$value]);
                    }
                }
            }

            preg_match_all("#([a-zA-Z]+)={([^}]+)}#", $node["tag"], $dynamic);
            preg_match_all("#([a-zA-Z]+)=[']([^']+)[']#", $node["tag"], $static);

            if (count($dynamic[0])) {
                foreach($dynamic[1] as $key => $value) {
                    $props["{$value}"] = $attributes["attr_{$key}"];
                }
            }

            if (count($static[1])) {
                foreach($static[1] as $key => $value) {
                    $props["{$value}"] = $static[2][$key];
                }
            }

            $code .= "pre_" . $node["name"] . "([" . PHP_EOL;

            foreach ($props as $key => $value) {
                $code .= "'{$key}' => {$value}," . PHP_EOL;
            }

            $code .= "])" . PHP_EOL;
        }
    }

    $code = Pre\Plugin\expand($code);
    $code = Pre\Plugin\formatCode($code);

    return $code;
}

// ...

// <?php
//
// $classNames = "foo bar";
// $message = "hello world";
//
// $thing = (
//     pre_div([
//         'className' => function () {
//             return "outer-div";
//         },
//         'nested' => pre_span([
//             'className' => "nested-span",
//         ]),
//     ])
// );
composer require pre/short-closures
require __DIR__ . "/vendor/autoload.php";

function parse($nodes) {
    $code = "";

    foreach ($nodes as $node) {
        if (isset($node["token"])) {
            $code .= $node["token"] . PHP_EOL;
        }

        if (isset($node["tag"])) {
            // ...

            $children = [];

            foreach ($node["children"] as $child) {
                if (isset($child["tag"])) {
                    $children[] = parse([$child]);
                }

                else {
                    $children[] = "\"" . addslashes($child["token"]) . "\"";
                }
            }

            $props["children"] = $children;

            $code .= "pre_" . $node["name"] . "([" . PHP_EOL;

            foreach ($props as $key => $value) {
                if ($key === "children") {
                    $code .= "\"children\" => [" . PHP_EOL;

                    foreach ($children as $child) {
                        $code .= "{$child}," . PHP_EOL;
                    }

                    $code .= "]," . PHP_EOL;
                }

                else {
                    $code .= "\"{$key}\" => {$value}," . PHP_EOL;
                }
            }

            $code .= "])" . PHP_EOL;
        }
    }

    $code = Pre\Plugin\expand($code);
    $code = Pre\Plugin\formatCode($code);

    return $code;
}

// ...

// <?php
//
// $classNames = "foo bar";
// $message = "hello world";
//
// $thing = (
//     pre_div([
//         "className" => function () {
//             return "outer-div";
//         },
//         "nested" => pre_span([
//             "className" => "nested-span",
//             "children" => [
//                 "with text",
//             ],
//         ]),
//         "children" => [
//             "a bit of text before",
//             pre_span([
//                 "children" => [
//                     "{$message} with a bit of extra text",
//                 ],
//             ]),
//             "a bit of text after",
//         ],
//     ])
// );
require __DIR__ . "/vendor/autoload.php";

function pre_div($props) {
    $code = "<div";

    if (isset($props["className"])) {
        if (is_callable($props["className"])) {
            $class = $props["className"]();
        }

        else {
            $class = $props["className"];
        }

        $code .= " class='{$class}'";
    }

    $code .= ">";

    foreach ($props["children"] as $child) {
        $code .= $child;
    }

    $code .= "</div>";

    return trim($code);
}

function pre_span($props) {
    $code = pre_div($props);
    $code = preg_replace("#^<div#", "<span", $code);
    $code = preg_replace("#div>$#", "span>", $code);

    return $code;
}

function parse($nodes) {
    // ...
}

$nodes = [
    0 => [
        'token' => '<?php

        $classNames = "foo bar";
        $message = "hello world";

        $thing = (',
    ],
    1 => [
        'tag' => '<div className={0} nested={1}>',
        'started' => 157,
        'attributes' => [
            0 => [
                'token' => '() => { return $classNames; }',
            ],
            1 => [
                'tag' => '<span className={0}>',
                'started' => 19,
                'attributes' => [
                    0 => [
                        'token' => '"nested-span"',
                    ],
                ],
                'name' => 'span',
                'children' => [
                    0 => [
                        'token' => 'with text',
                    ],
                ],
            ],
        ],
        'name' => 'div',
        'children' => [
            0 => [
                'token' => 'a bit of text before',
            ],
            1 => [
                'tag' => '<span>',
                'started' => 195,
                'name' => 'span',
                'children' => [
                    0 => [
                        'token' => '{$message} with a bit of extra text',
                    ],
                ],
            ],
            2 => [
                'token' => 'a bit of text after',
            ],
        ],
    ],
    2 => [
        'token' => ');',
    ],
    3 => [
        'token' => 'print $thing;',
    ],
];

eval(substr(parse($nodes), 5));

// <div class='foo bar'>
//     a bit of text before
//     <span>
//         hello world with a bit of extra text
//     </span>
//     a bit of text after
// </div>

Integrating with Pre

use Silex\Application;
use Silex\Provider\SessionServiceProvider;
use Symfony\Component\HttpFoundation\Request;

use App\Component\AddTask;
use App\Component\Page;
use App\Component\TaskList;

$app = new Application();
$app->register(new SessionServiceProvider());

$app->get("/", (Request $request) => {
    $session = $request->getSession();

    $tasks = $session->get("tasks", []);

    return (
        <Page>
            <TaskList>{$tasks}</TaskList>
            <AddTask></AddTask>
        </Page>
    );
});

$app->post("/add", (Request $request) => {
    $session = $request->getSession();

    $id = $session->get("id", 0);
    $tasks = $session->get("tasks", []);

    $tasks[] = [
        "id" => $id++,
        "text" => $request->get("text"),
    ];

    $session->set("id", $id);
    $session->set("tasks", $tasks);

    return $app->redirect("/");
});

$app->get("/remove/{id}", (Request $request, $id) => {
    $session = $request->getSession();

    $tasks = $session->get("tasks", []);

    $tasks = array_filter($tasks, ($task) => {
        return $task["id"] !== (int) $id;
    });

    $session->set("tasks", $tasks);

    return $app->redirect("/");
});

$app->run();
require __DIR__ . "/../vendor/autoload.php";

Pre\Plugin\process(__DIR__ . "/../server.pre");
php -S localhost:8080 -t public public/index.php
namespace App\Component;

use InvalidArgumentException;

class Page
{
    public function render($props)
    {
        assert($this->hasValid($props));

        { $children } = $props;

        return (
            "<!doctype html>".
            <html lang="en">
                <body>
                    {$children}
                </body>
            </html>
        );
    }

    private function hasValid($props)
    {
        if (empty($props["children"])) {
            throw new InvalidArgumentException("page needs content (children)");
        }

        return true;
    }
}
namespace App\Component;

class TaskList
{
    public function render($props)
    {
        { $children } = $props;

        return (
            <ul className={"task-list"}>
                {$this->children($children)}
            </ul>
        );
    }

    private function children($children)
    {
        if (count($children)) {
            return {$children}->map(($task) => {
                return (
                    <Task id={$task["id"]}>{$task["text"]}</Task>
                );
            });
        }

        return (
            <span>No tasks</span>
        );
    }
}
  1. A literal value expression, like "task-list"
  2. An array (or key-less pre/collection object), like ["first", "second"]
  3. An associative array (or keyed pre/collection object), like ["first" => true, "second" => false]
namespace App\Component;

use InvalidArgumentException;

class Task
{
    public function render($props)
    {
        assert($this->hasValid($props));

        { $children, $id } = $props;

        return (
            <li className={"task"}>
                {$children}
                <a href={"/remove/{$id}"}>remove</a>
            </li>
        );
    }

    private function hasValid($props)
    {
        if (!isset($props["id"])) {
            throw new InvalidArgumentException("task needs id (attribute)");
        }

        if (empty($props["children"])) {
            throw new InvalidArgumentException("task needs text (children)");
        }

        return true;
    }
}
namespace App\Component;

class AddTask
{
    public function render($props)
    {
        return (
            <form method={"post"} action={"/add"} className={"add-task"}>
                <input name={"text"} type={"text"} />
                <button type={"submit"}>add</button>
            </form>
        );
    }
}
$app->post("/add", (Request $request) => {
    $session = $request->getSession();

    $id = $session->get("id", 1);
    $tasks = $session->get("tasks", []);

    $tasks[] = [
        "id" => $id++,
        "text" => $request->get("text"),
    ];

    $session->set("id", $id);
    $session->set("tasks", $tasks);

    return $app->redirect("/");
});

$app->get("/remove/{id}", (Request $request, $id) => {
    $session = $request->getSession();

    $tasks = $session->get("tasks", []);

    $tasks = array_filter($tasks, ($task) => {
        return $task["id"] !== (int) $id;
    });

    $session->set("tasks", $tasks);

    return $app->redirect("/");
});

Comments

Popular posts from this blog

Memory leak in 7.x json_decode()? Best Php Training Trivandrum

Memory leak in 7.x json_decode()? There appears to be a memory leak in 7.x json_decode(). I've uploaded a huge JSON file to demonstrate the problem. Here is the sample code: <?php echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; $json = json_decode(file_get_contents('http://zaremedia.com/big.json')); echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; unset($json); echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; Below is output from 7.x and then 5.6: // Running on 7.0 and 7.1 349608 : 2097152 27245512 : 29360128 375552 : 29360128 The process starts with 0.3mb used / 2.0mb allocated. After json_decode(), it's 27.2 / 29.4mb, after unset, it's 3.7mb / 29.4mb -- The second value (memory allocated by php via emalloc()) has not been freed, though PHP's gc has correctly freed up the object usage. // Running on 5.6 221136 : 262144 31577064 : 35913728 420104 : 86507...

PHP-FPM tuning: Using ‘pm static’ for max performance best php training trivandrum

PHP-FPM tuning: Using ‘pm static’ for max performance Lets take a very quick look at how best to setup PHP-FPM for high throughput, low latency and a more stable use of CPU and memory. By default, most setups have PHP-FPM’s PM (process manager) string set to  dynamic  and there’s also the common advice to use  ondemand  if you suffer from available memory issues. However, lets compare the two management options based on php.net’s documentation and also compare my favorite for high traffic setups…  static  pm: pm = dynamic  – the number of child processes is set dynamically based on the following directives:  pm.max_children, pm.start_servers,pm.min_spare_servers, pm.max_spare_servers . pm = ondemand  – the processes spawn on demand (when requested, as opposed to dynamic, where pm.start_servers are started when the service is started. pm = static  – the number of child processes is fixed by...

How does the PHP Realpath Cache work and how to configure it? best php training trivandrum

How does the PHP Realpath Cache work and how to configure it? The realpath cache in PHP is often overlooked and its exact workings are a bit of a mystery to many developers, fueled by a lot of explanations on the web that are just plain wrong. How exactly is the realpath cache working and at which level of PHP? There has been some buzz around realpath cache in the last weeks, so it is a hot topic to look into. First, The PHP 7.2 changelogs contain a small note about the realpath cache size, raising the question what about the previous default in pre 7.2 deployments and if you should look into changing it: realpath_cache_size: Set to 4096k by default The previous default was just 16k, a 256x increase is massive! Second, the blog post " Is it all Opcache's fault? " on the facile.it Engineering blog identifies the realpath cache as a potential problem during symlink deployments. Knowing about this issue is important when building your own deploy strategy. ...