php_world
This module extends Deno world with PHP, by running commandline PHP interpreter in the background.
There are several possible reasons to use the php_world
:
- If you have a large PHP application, and you wish to convert it to Javascript/Typescript, but it’s impossible to achieve at once. In this case
php_world
allows you to start writing new code in Javascript/Typescript, and convert each part of the application later, as desired. - If you want to benefit from PHP functionality or third-party PHP libraries/SDKs or database drivers.
Requirements
PHP CLI must be installed on your system, and the php
command must correspond to the PHP interpreter.
Limitations
- Unfortunately it’s impossible to automatically garbage-collect PHP object handles, so
delete
must be used explicitly (see below). - Requires
--unstable
flag, likedeno run --unstable --allow-run --allow-read --allow-write ...
.
Examples
Usage
import {f, g, c} from './mod.ts';
// ...
// and at last, terminate the interpreter
await f.exit();
There are 3 logical namespaces:
f
contains all the PHP functions.g
contains global constants and variables.c
contains classes.
Calling functions
Each function becomes async, because calling it involves IPC (interprocess communication) with the background PHP interpreter.
import {f} from './mod.ts';
const {eval: php_eval, phpversion, class_exists, exit} = f;
console.log(await phpversion());
await php_eval('class Hello {}');
console.log(await class_exists('Hello'));
await exit();
At the end of Deno script, it’s nice to call exit()
. This function terminates the interpreter, and frees all the resources. After this function called, the php_world
can be used again, and a new instance of the interpreter will be spawned. It’s OK to call exit()
several times.
Global constants
Constant’s value must be awaited-for.
import {f, g, c} from './mod.ts';
console.log(await g.PHP_VERSION);
console.log((await g.FAKE) === undefined); // unexisting constants have "undefined" value
Global variables
Like constants, variables are present in the g
namespace, but their names must begin with a ‘$’.
Variable’s value must be awaited-for. But setting new value returns immediately (and doesn’t imply synchronous operations - the value will be set in the background, and there’s no result that we need to await for).
import {f, g, c} from './mod.ts';
console.log((await g.$ten) === undefined); // unexisting variables have "undefined" value
g.$ten = 10;
console.log(await g.$ten);
Classes
Classes are present in the c
namespace.
Class-static constants
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval('class Value {const TEN = 10;}');
console.log((await Value.NINE) === undefined); // unexisting constants have "undefined" value
console.log(await Value.TEN);
Class-static variables
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval('class Value {static $ten = 10;}');
console.log((await Value.$nine) === undefined); // unexisting variables have "undefined" value
console.log(await Value.$ten);
Class-static methods
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval
( ` class Value
{ static function get_ten()
{ return 10;
}
}
`
);
console.log(await Value.get_ten());
Class construction and destruction
To create a class instance, call the constructor, and await the result. It returns handler to remote PHP object.
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval('class Value {}');
let value = await new Value;
Each instance created with new
, must be destroyed with delete
.
delete value.this;
Instance variables
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval('class Value {public $ten;}');
let value = await new Value;
value.ten = 10;
console.log(await value.ten);
delete value.this;
Instance methods
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {Value} = c;
await php_eval
( ` class Value
{ public $var;
function get_twice_var()
{ return $this->var * 2;
}
}
`
);
let value = await new Value;
value.var = 10;
console.log(await value.get_twice_var());
delete value.this;
Namespaces
import {f, g, c} from './mod.ts';
const {eval: php_eval} = f;
const {MainNs} = c;
await php_eval
( ` namespace MainNs;
class Value
{ public $var;
function get_twice_var()
{ return $this->var * 2;
}
}
`
);
let value = await new MainNs.Value;
value.var = 10;
console.log(await value.get_twice_var());
delete value.this;
Running several PHP interpreters in parallel
import {f, g, c, PhpInterpreter} from './mod.ts';
let int_1 = new PhpInterpreter;
let int_2 = new PhpInterpreter;
let pid_0 = await f.posix_getpid();
let pid_1 = await int_1.f.posix_getpid();
let pid_2 = await int_2.f.posix_getpid();
console.log(`${pid_0}, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mrow><mi>p</mi><mi>i</mi><msub><mi>d</mi><mn>1</mn></msub></mrow><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">{pid_1}, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mord mathnormal">i</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3011em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span><span class="mpunct">,</span></span></span></span>{pid_2}`);
await f.exit();
await int_1.f.exit();
await int_2.f.exit();