461
308

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP って JavaScript に変換できるの?できるわけないだろ! babel-preset-php ってのが今日リリースされた?これまさか・・・。ファーーーーーーーーーーーwwwwwwwwwwww

Posted at

PHP (7) を Javascript (ES7) に変換するための Babel プリセット babel-preset-php が本日 (2017-7-12) リリースされたみたいです:dizzy_face::sweat_drops:

正直、「は?凄すぎだろ (小並感) 」という言葉しか出てきませんww

とりあえず面白そうなので試してみます!

使い方

公式の通りですが、プロジェクトを作成し babel-clibabel-preset-php をインストールします。

cd path/to/project
npm init -y
npm i -g babel-cli
npm i -S babel-preset-php

.babelrc を作成します。

.babelrc
{
  "presets": ["php"]
}

サンプルの PHP ファイルとして file.php を作成します。

file.php
<?php
define('FOO', max(floatval($c), strlen("foo")));
$bar['x'][][$b] = json_encode(__FILE__);
class Foo extends Bar\Baz {
  var $z = "hello" . "world";
  function __construct($some = array(7)) {
    parent::__construct(func_get_args());
    self::${$k} = "{$this->z[10]}";
  }
}

準備ができました!

後は以下のように PHP から JavaScript にトランスパイルすると、

babel file.php -o file.js

PHP ファイルが Babel によって変換された以下のような Javascript ファイルが作成されます。

file.js
const FOO = Math.max(+c, "foo".length);
bar.x.push({
  [b]: JSON.stringify(__filename)
});

class Foo extends Bar.Baz {
  constructor(some = [7]) {
    super(arguments);
    this.z = "hello" + "world";
    this.constructor[k] = `${this.z[10]}`;
  }

};

凄すぎる・・・:joy:

サポートされていない言語機能 等もあるのでもっと詳しく知りたい方は公式を参照してください。

もっと試す!

毎回複数の PHP ファイルを JavaScript ファイルへ babel-cli で叩いてトランスパイルするのが面倒だったため、一括でトランスパイル出来るよう以下のプロジェクトを作成しました:thumbsup:

kotarella1110/babel-preset-php-sample

以下では、変換前の PHP ファイルと変換後の JavaScript ファイルを表示しています。実際に変換されたファイルを確認したい場合は、上記のプロジェクトをクローンして yarn build を実行することで確認できます:laughing:

試してみた感想としては、 想像より言語機能をサポートしていて凄い と思いました。さっきから凄いしか言ってないww

AST translation

Expressions

src/translation/expressions.php
<?php
2 + 2;
$a = null;
$a .= 'x';
$a = NuLL;
$a + 1;
$a = $b = 1;
$c = $d ? 1 : 2;
$d ?: 2;
$a[1] + $b[Z];
$b[$foo['Z']];
"f\\no\\\\o";
bar();
eval($lol);
(int)"1";
(float)"1";
(bool)"1";
(string)$x;
(object)$x;
(array)$x;
dist/translation/expressions.js
var b;
2 + 2;
var a = undefined;
a += "x";
a = undefined;
a + 1;
a = b = 1;
var c = d ? 1 : 2;
d ? d : 2;
a[1] + b[Z];
b[foo.Z];
"f\\no\\\\o";
bar();
eval(lol);
+"1";
+"1";
!!"1";
String(x);
Object(x);
Array.from(x);

Builtins

src/translation/builtins.php
<?php
echo "foo",$bar;
print "foo";
isset($x[$y]);
isset($x[$y], $z);
empty($x[$y]);
unset($x[$y]);
function is_bool(){}; is_bool($x);
__FILE__;
__DIR__;
function foo(){__FUNCTION__;}
__LINE__;
__LINE__;
dist/translation/builtins.js
echo("foo", bar);
print("foo");
undefined !== x[y];
undefined !== x[y] && undefined !== z;
!x[y];
delete x[y];

function is_bool() {};

is_bool(x);
__filename;
__dirname;

function foo() {
  "foo";
};

12;
13;

Array and list

src/translation/arrayAndList.php
<?php
$a = []; $a['x'] = 2;
$a = [1,2]; $a = 2;
$a = ['x' => 1];
$a = [' ' => 1];
$a = [$z => 1];
$a = [$z => 1, 'a', 'b'];
$a = ['a', $z => 1, 'b'];
$a = ['a', 3 => 'c', 'b'];
list($a, $b) = [1,2];
list($a,,$b) = [1,2];
$a[] = 1;
foo($a['b'][]);
$a[1][] = 1;
$a['b']['c'][]['d']['e'] = 1;
$a[CON] = 1;
$a->foo[] = 1;
$a->{$foo}[] = 1;
dist/translation/arrayAndList.js
var b;
var a = Array();
a.x = 2;
a = [1, 2];
a = 2;
a = {
  x: 1
};
a = {
  " ": 1
};
a = {
  [z]: 1
};
a = {
  [z]: 1,
  0: "a",
  1: "b"
};
a = {
  0: "a",
  [z]: 1,
  1: "b"
};
a = {
  0: "a",
  3: "c",
  4: "b"
};
[a, b] = [1, 2];
[a,, b] = [1, 2];
a.push(1);
foo(a.b);
a[1].push(1);
a.b.c.push({
  d: {
    e: 1
  }
});
a[CON] = 1;
a.foo.push(1);
a[foo].push(1);

Templates

src/translation/templates.php
<?php
"foo$bar";
"foo$bar baz";
"${not_varvar}";
"foo${bar}$quz";
"foo${2+2}";
$$var;
"foo${$varvar}";
dist/translation/templates.js
`foo${bar}`;
`foo${bar} baz`;
`${not_varvar}`;
`foo${bar}${quz}`;
`foo${global[2 + 2]}`;
global[var];
`foo${global[varvar]}`;

Functions

src/translation/functions.php
<?php
function bar($foo) {return $foo + 1;}
function bar($foo) {$foo = 2;}
function bar(TypeName $foo) {$foo = 2;}
$a=1; function bar() {$a = 2;}
$z = function() use($x){$x=1;$y=2;};
$z = function(){static $n;};
if ($a = 1) {if ($b = 2 && $c = 2) {}}
dist/translation/functions.js
function bar(foo) {
  return foo + 1;
};

function bar(foo) {
  foo = 2;
};

function bar(foo: TypeName) {
  foo = 2;
};

var a = 1;

function bar() {
  var a = 2;
};

var z = () => {
  x = 1;
  var y = 2;
};

z = () => {
  if (!("_static_closure_1_n" in global)) _static_closure_1_n = undefined;
};

if (a = 1) {
  var b, c;

  if (b = 2 && (c = 2)) {}
}

Loops

src/translation/loops.php
<?php
for($x=1; $x < 10; $x++, $y++){}
foreach($arr as $el){}
foreach([1,2,3] as $el){}
foreach($arr as $k => $v){}
foreach(func() as $k => $v){}
while(true) { $a--; break; }
do{if(false)continue;}while(true);
dist/translation/loops.js
for (var x = 1; x < 10; x++, y++) {}

for (var el of Object.values(arr)) {}

for (var el of [1, 2, 3]) {}

for (var k in arr) {
  var v = arr[k];
}

{
  let _tmp_0 = func();

  for (var k in _tmp_0) {
    var v = _tmp_0[k];
  }
}

while (true) {
  a--;
  break;
}

do {
  if (false) continue;
} while (true);

Statements

src/translation/statements.php
<?php
switch($c) {case "a": case "b": return $c; default: return $z;}
require "foo";
include_once "foo";
if (false) while(true) { $a--; }
if (false) if (true) { --$a; }
exit(1);
dist/translation/statements.js
switch (c) {
  case "a":
  case "b":
    return c;

  default:
    return z;
}

require("foo");

require("foo");

if (false) while (true) {
  a--;
}
if (false) if (true) {
  --a;
}
throw die(1);

Exceptions

src/translation/exceptions.php
<?php
try {hey();} catch(Exception $e) {bye($e);}
try{}catch(\Exception $e){}
throw new Error();
try{}catch(Foo $e){$a=1;}
function foo(){static $z; try{}catch(Foo $f){$f=1;}catch(Bar $b){$b=1;$z=1;}}
try{}catch(Foo | Bar $e){$a=1;}
try{}catch(Foo $e){}catch(\Exception $z){$a=1;}
dist/translation/exceptions.js
try {
  hey();
} catch (e) {
  bye(e);
}

try {} catch (e) {}

throw new Error();

try {} catch (e) {
  if (e instanceof Foo) {
    var a = 1;
  }
}

function foo() {
  if (!("_static_foo_z" in global)) _static_foo_z = undefined;

  try {} catch (f) {
    if (f instanceof Foo) {
      f = 1;
    } else if (f instanceof Bar) {
      f = 1;
      _static_foo_z = 1;
    }
  }
};

try {} catch (e) {
  if (e instanceof Foo || e instanceof Bar) {
    var a = 1;
  }
}

try {} catch (e) {
  if (e instanceof Foo) {} else if (true) {
    var a = 1;
  }
}

Static

src/translation/static.php
<?php
function foo() {static $bar; $bar=1;}
function foo() {global $bar; $bar=1;}
function foo() {static $bar,$baz=1; $bar=1;}
dist/translation/static.js
function foo() {
  if (!("_static_foo_bar" in global)) _static_foo_bar = undefined;
  _static_foo_bar = 1;
};

function foo() {
  if (!("bar" in global)) bar = undefined;
  bar = 1;
};

function foo() {
  {
    if (!("_static_foo_bar" in global)) _static_foo_bar = undefined;
    if (!("_static_foo_baz" in global)) _static_foo_baz = 1;
  }
  _static_foo_bar = 1;
};

Class

src/translation/class.php
<?php
new Foo($bar);
class Foo {};
class Foo2 extends Bar {};
class Foo3 extends Foo\Bar {};
class Foo4 extends Foo\Bar\Baz\Quz {};
class Foo5 extends \Foo\Bar {};
class Foo6 {function __construct($bla){$this->foo=1;}};
class Foo7 {function __construct($bla){$this->${foo}=1;}};
class Foo8 {function __construct($bla){parent::foo();}};
class Foo9 {function __construct($bla){parent::__construct();}};
class Foo10 {function bar($z){$this->{$meta} = 2;}};
class Foo11 {static function bar($z){self::bar();}};
class Foo12 {function bar(){self::CON;}};
class Foo13 {private function bar($z=1){} protected function quz(){$this->bar();}};
dist/translation/class.js
new Foo(bar);

class Foo {};

class Foo2 extends Bar {};

class Foo3 extends Foo.Bar {};

class Foo4 extends Foo.Bar.Baz.Quz {};

class Foo5 extends global.Foo.Bar {};

class Foo6 {
  constructor(bla) {
    this.foo = 1;
  }

};

class Foo7 {
  constructor(bla) {
    this[foo] = 1;
  }

};

class Foo8 {
  constructor(bla) {
    super.foo();
  }

};

class Foo9 {
  constructor(bla) {
    super();
  }

};

class Foo10 {
  bar(z) {
    this[meta] = 2;
  }

};

class Foo11 {
  static bar(z) {
    this.bar();
  }

};

class Foo12 {
  bar() {
    this.constructor.CON;
  }

};

class Foo13 {
  bar(z = 1) {}

  quz() {
    this.bar();
  }

};

Class props

src/translation/classProps.php
<?php
class Foo {const Z=1;}
class Foo2 {static $z=1;}
class Foo3 {private static $z=1; static function x(){self::$z;self::${z()};}}
class Foo4 {var $z=1;}
class Foo5 extends Bar {var $z=1;}
class Foo6 extends Bar {var $z=1; function __construct(){hi();}}
class Foo7 extends Bar {var $z=1; function __construct(){parent::__construct();hi();}}
dist/translation/classProps.js
class Foo {
  static Z = 1;
};

class Foo2 {
  static z = 1;
};

class Foo3 {
  static z = 1;

  static x() {
    this.z;
    this[z()];
  }

};

class Foo4 {
  constructor() {
    this.z = 1;
  }

};

class Foo5 extends Bar {
  constructor() {
    super(...arguments);
    this.z = 1;
  }

};

class Foo6 extends Bar {
  constructor() {
    this.z = 1;
    hi();
  }

};

class Foo7 extends Bar {
  constructor() {
    super();
    this.z = 1;
    hi();
  }

};

Types

src/translation/types.php
<?php
class Foo {function annotated($untyped, Cls\Name $class, self $self, array $array, callable $callable, bool $bool, float $float, int $int, string $string, iterable $iter) {}}
class Foo2 {function annotated($untyped = null, Cls\Name $class = null, self $self = null, array $array = null, callable $callable = null, bool $bool = null, float $float = null, int $int = null, string $string = null, iterable $iter = null) {}}
class Foo3 {function annotated($untyped, ?Cls\Name $class, ?self $self, ?array $array, ?callable $callable, ?bool $bool, ?float $float, ?int $int, ?string $string, ?iterable $iter) {}}
dist/translation/types.js
class Foo {
  annotated(untyped, class: Cls.Name, self: Foo, array: {} | any[], callable: Function, bool: boolean, float: number, int: number, string: string, iter: {} | any[]) {}

};

class Foo2 {
  annotated(untyped = undefined, class: ?Cls.Name = undefined, self: ?Foo2 = undefined, array: ?{} | any[] = undefined, callable: ?Function = undefined, bool: ?boolean = undefined, float: ?number = undefined, int: ?number = undefined, string: ?string = undefined, iter: ?{} | any[] = undefined) {}

};

class Foo3 {
  annotated(untyped, class: ?Cls.Name, self: ?Foo3, array: ?{} | any[], callable: ?Function, bool: ?boolean, float: ?number, int: ?number, string: ?string, iter: ?{} | any[]) {}

};

AST modification

Expressions

src/modification/expressions.php
<?php
is_string($x);
is_bool($x);
dist/modification/expressions.js
"string" === typeof x;
"boolean" === typeof x;

Builtins

src/modification/builtins.php
<?php
is_nan($x);
is_float($x);
is_object($x);
is_array($x);
trim($x);
function trim(){}; trim($x);
ord($x);
ord($x["z"]);
ord($x[5]);
chr($x);
substr($x,1,2);
str_replace(1,2,$x);
str_replace(1,2,$x,1);
str_replace(1,2,$x,$z);
trim($x,"x");
$_ENV["X"];
dist/modification/builtins.js
Number.isNaN(x);
"number" === typeof x;
"object" === typeof x;
Array.isArray(x);
trim(x);

function trim() {};

trim(x);
x.charCodeAt(0);
x.z.charCodeAt(0);
x.charCodeAt(5);
String.fromCharCode(x);
x.substr(1, 2);
str_replace(1, 2, x);
x.replace(1, 2);
str_replace(1, 2, x, z);
trim(x, "x");
process.env.X;

Preg

src/modification/preg.php
<?php
preg_replace("#t\\*ex*t#i", $y, $z);
preg_replace_callback("/(reg)/", $y, $z);
preg_replace("$dynamic", $y, $z);
dist/modification/preg.js
z.replace(/t\*ex*t/gi, y);
z.replace(/(reg)/g, y);
preg_replace(`${dynamic}`, y, z);

Array

src/modification/array.php
<?php
array_key_exists($k,$a);
in_array($needle, $haystack);
dist/modification/array.js
k in a;
-1 !== haystack.indexOf(needle);

Define

src/modification/define.php
<?php
defined('foo');
defined('%z');
define('foo', 2);
define('1foo', 2);
function b(){define('foo', 2);}
function b(){define('foo bar', 2);}
define("foo$bar", "$baz quz");
dist/modification/define.js
"undefined" !== typeof foo;
undefined !== global["%z"];
const foo = 2;
global["1foo"] = 2;

function b() {
  global.foo = 2;
};

function b() {
  global["foo bar"] = 2;
};

global[`foo${bar}`] = `${baz} quz`;

Functions

src/modification/functions.php
<?php
function bar() {$a = func_get_args();}
dist/modification/functions.js
function bar() {
  var a = arguments;
};

Class

src/modification/class.php
<?php
class Foo extends Exception {}
dist/modification/class.js
class Foo extends Error {};

Standard funcs

src/modification/standardFuncs.php
<?php
count($a);
function count() {}; count($a);
sort($a);
usort($a, function($a,$b){
  return 1;}
);
array_pop($a);
array_keys($a);
array_values($a);
array_shift($a);
pow(1);
max(1,2);
$max = function(){}; max(1,2);
array_unshift($a,$b,$c);
array_push($a,1,2+2,3);
array_slice($a,1,2);
array_reverse($a);
array_splice($a,1,2,$z);
array_walk($a,$z,1);
array_reduce($a,function(){});
array_filter($a,function(){});
array_map(function(){},$a);
implode('str', $a);
explode('str', $a, 2);
function_exists('bla');
function_exists($z);
class_exists($z);
dist/modification/standardFuncs.js
count(a);

function count() {};

count(a);
a.sort();
a.sort((a, b) => {
  return 1;
});
a.pop();
Object.keys(a);
Object.values(a);
a.shift();
Math.pow(1);
max(1, 2);

var max = () => {};

max(1, 2);
a.unshift(b, c);
a.push(1, 2 + 2, 3);
a.slice(1, 2);
a.reverse();
a.splice(1, 2, z);
a.forEach(z, 1);
a.reduce(() => {});
a.filter(() => {});
a.map(() => {});
a.join("str");
a.split("str", 2);
"function" === typeof bla;
"function" === typeof global[z];
"function" === typeof global[z];

え?これどこで使えるの?

マジで分かりませんww が、 AWS Lambda を PHP で書いたぞ!:sunglasses:とドヤることぐらいは出来るかもしれませんww

461
308
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
461
308

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?