phpscriptjs
v0.1.0
Published
PHPScript — real PHP syntax, compiled to JavaScript. Toy language + live browser playground.
Maintainers
Readme
PHPScript
Real PHP syntax, compiled to JavaScript. A toy language where you write actual .php files
— <?php ... ?>, <?= ... ?>, HTML templates, classes, foreach, the whole vibe —
and the compiler spits out portable JavaScript you can run with Node or in the browser.
<?php
$langs = ['PHP', 'JS', 'TypeScript'];
foreach ($langs as $l): ?>
<li><?= strtoupper($l) ?></li>
<?php endforeach; ?>Install
npm install -g phpscriptjsThis installs a php binary.
Heads up — the CLI is literally named
php. That's part of the joke. If real PHP is already on your$PATH, whichever comes first wins. If you want both, alias PHPScript to something else:alias phps='$(npm bin -g)/php' # or wherever npm put it
Quick start
# Run a file
php hello.php
# Or explicitly
php run hello.php
# Compile to .js
php build src/ -o dist/
# Watch mode
php watch src/
# Launch the live browser playground at http://localhost:5173
php serveInline one-liners work too:
php -e '<?php echo "Hello " . strtoupper("world") . "!";'Browser playground
The repo ships with a live playground: PHPScript on the left, rendered HTML (or raw output, or compiled JS) on the right, recompiled as you type.
npm run dev
# or: php serve --port 5173Then open http://localhost:5173. Share a snippet by clicking Share link — the code is
encoded into the URL hash.
Language features
Tags & output
<?php ... ?>,<?= expr ?>, short<? ... ?>echo,print- Trailing
?>is optional
Literals
- Numbers,
true/false/null 'single'strings (no interpolation)"double"strings with$varand{$expr}interpolation- Arrays:
[1, 2, 3]-> JS array,['a' => 1]-> JS object, mixed -> object
Variables
$namemaps 1:1 to JS$name- Reserved-word collisions (e.g.
$class) are mangled safely
Operators
- Arithmetic, comparison (
==,===,!=,!==), logical (&&,||,!,and,or,xor) - String concat
.compiles to JS+with string coercion - Null coalescing
??, ternary?:, Elvis?:, spaceship<=> - Pre/post
++/--, compound assigns (+=,.=, ...)
Control flow
if / elseif / else, both brace and alternativeif: / elseif: / else: / endif;formswhile,do-while,for,foreach(bothas $vandas $k => $v)switch/case/default,break,continue,return
Functions & classes
function f($a, $b = 1, ...$rest)— defaults + rest- Anonymous:
function ($x) use ($y) { ... }, arrow:fn ($x) => $x * 2 class Foo extends Bar { public $x = 1; function m() { $this->x; } }→ ES6 class$obj->m(),$obj->prop,Foo::staticM(),new Foo(...),self::,parent::,static::,$this
Superglobals & builtins (in src/runtime.js)
$_GET,$_POST,$_SERVER,$_ENV(populated fromprocess.envin Node, empty in the browser)- Strings:
strlen,strtoupper,strtolower,trim,ltrim,rtrim,str_replace,substr,explode,implode/join,sprintf(minimal),str_repeat,str_pad,str_contains,str_starts_with,str_ends_with,number_format,ucfirst,lcfirst,ucwords,htmlspecialchars - Arrays:
count,array_map,array_filter,array_reduce,array_keys,array_values,in_array,array_push,array_pop,array_shift,array_unshift,array_merge,array_reverse,array_slice,array_sum,array_unique,range,sort - Types & misc:
isset,empty,is_array,is_string,is_numeric,is_int,is_bool,is_null,intval,floatval,strval,boolval,abs,min,max,round,floor,ceil,print_r,var_dump,json_encode,json_decode,date,time
Example: examples/template.php
<?php
$users = [
['name' => 'Ada', 'age' => 36],
['name' => 'Alan', 'age' => 41],
];
function greet($u) { return "Hi, " . $u['name'] . "!"; }
?>
<!doctype html>
<h1>Users (<?= count($users) ?>)</h1>
<ul>
<?php foreach ($users as $u): ?>
<li><?= greet($u) ?> — age <?= $u['age'] ?></li>
<?php endforeach; ?>
</ul>Run it:
php examples/template.phpCompiles to (roughly):
const { __echo, __str, __entries, count } = require('/abs/path/to/runtime.js');
let $users = [
{ name: 'Ada', age: 36 },
{ name: 'Alan', age: 41 },
];
function greet($u) { return __str('Hi, ') + __str($u['name']) + __str('!'); }
__echo("<!doctype html>\n<h1>Users (");
__echo(count($users));
__echo(")</h1>\n<ul>\n");
for (const $u of __values($users)) {
__echo("\n <li>");
__echo(greet($u));
__echo(" — age ");
__echo($u['age']);
__echo("</li>\n");
}
__echo("\n</ul>\n");Not supported (explicit non-goals)
PHPScript is a demo, not a migration tool. It doesn't implement:
- PHP's full type-juggling rules for
==(JS==is used as an approximation) - References (
&$x) — parsed, treated as normal bindings - Traits, interfaces, enums, attributes
- Generators /
yield preg_*regex family, fullsprintfformat specifiers- Namespaces,
useimports, autoloading - Any of the standard PHP extensions (MySQL, GD, curl, ...)
If you need real PHP, use real PHP.
Architecture
.php source
│
▼
┌──────┐ tokens ┌────────┐ AST ┌─────────┐ JS
│Lexer │──────────▶│ Parser │────────▶│ Codegen │───────▶ Node (stdout)
└──────┘ └────────┘ └─────────┘ Browser (iframe)
│
runtime.js ────┘- Lexer (
src/lexer.js): dual-mode. EmitsRAW_TEXTtokens for HTML between PHP tags; flips into code mode on<?php/<?=/<?and back on?>. - Parser (
src/parser.js): hand-written recursive-descent + Pratt expression parser with proper PHP precedence. - Codegen (
src/codegen.js): walks the AST and emits JavaScript. Variable hoisting, string interpolation to template literals,foreachtofor ... of, classes to ES6 classes, etc. - Runtime (
src/runtime.js): the PHP standard library, implemented in plain JS. Imported by generated code, inlined into the browser bundle. - CLI (
src/cli.js):run,build,watch,serve. - Playground (
web/): static HTML + CodeJar editor + Prism highlighting + sandboxed<iframe>preview. Recompiles on every keystroke.
Scripts
npm test # run the example test suite
npm run build:web # bundle the browser-safe compiler via esbuild
npm run dev # shortcut for `php serve`License
MIT
