这个问题和how to execute javascript in javascript, or php in php 非常相似,答案是你可以eval它。如果 php 可以 eval javascript 并且 javascript 可以 eval php,我们就不会有这个讨论。
为了让 JavaScript 评估 PHP,它必须将 PHP 代码解析为表示脚本的结构。JavaScript 可以使用 JavaScript 对象表示法(不是 JSON 格式,而是实际表示)轻松完成此操作,并在功能上分解脚本。
这是 JavaScript 解释 PHP 的一个天真的例子(一个更诚实的例子不会那么做作,而是将 php 解析成它自己的类似 JSON 的表示或可能的字节码,然后在 php 的 javascript 模拟上解释这个类似 json 的表示或字节码虚拟机,但仍然如此):
(() => {
'use strict';
var phpSnippet = 'echo "Hi";';
var partialPHPEval = (phpCode) => {
var regex = /echo[\s]["]([^"]*)["][;]/mg;
var match = null;
phpCode = phpCode.trim();
if ((match = phpCode.match(regex))) {
var code = (match[0].replace(regex, "(console.log('$1'))"));
console.log('converted to "' + code + '"');
eval(code);
}
};
partialPHPEval(phpSnippet);
})();
问题是 PHP 不是 javascript,而且它的 eval 比 javascript 弱得多。
这会产生一个问题,即 php 可以轻松地发出将 javascript 标记为 PHP 的请求:JavaScript 可以轻松创建任何内容的“JSONified”版本(只要它不是本机的),因此您可以让 PHP 向 nodejs 服务器发送请求使用您要评估的脚本。
例如:(PHP代码)
include "some_file_defining_jsEval.php";
$wantedObject = function($a) {
return $a;
};
$resultingObject = jsEval(
'(function(a) {' .
' return a;' .
'})'
);
echo $resultingObject("Hello, World!");
JavaScript 可以通过执行以下操作轻松将其评估为“函数对象”:
var functionObject = eval(
'(function(a) {' +
' return a;' +
'})'
);
console.log('your code is: ' + '(' + functionObject.toString() + ')');
如您所见,js 可以轻松地将其解析为一个对象,然后再解析为一个字符串,有一个小麻烦,即必须添加 '(' 和 ')' 以使其 eval() 不会导致错误“Uncaught SyntaxError : 意外的标记 (”。
无论如何,类似的事情可以在 PHP 中完成:
<?php
$functionObject = eval(
'return function($a) {' .
' return $a;' .
'};'
);
echo $functionObject("hi");
?>
知道了这一点,您必须让 JavaScript 将 JavaScript 函数对象转换为 PHP 函数对象,或者走简单的翻译路线。
问题在于 JavaScript(ES6) 比 PHP 更具表现力(5.6、7 可能更好,但如果没有 service pack 1 windows 7,它就无法运行,所以我无法在这台计算机上运行它)。这反过来意味着 JavaScript 有很多功能,而 PHP 没有,例如:
(function() {
console.log("Hello World");
})();
不适用于 PHP 5.6,因为它不支持自执行函数。这意味着您需要做更多的工作才能将其翻译成:
call_user_func(function() {
echo "hello, world!" . "\n";
});
还有一些问题是,PHP 并没有像 javascript 那样真正使用原型,因此很难对其进行翻译。
无论如何,最终 php 和 javascript 非常相似,以至于您基本上可以在另一个中使用一个例外。
例如:(PHP)
/* 就我所知,不能描述为函数,因为不是原型 */ class console { static function log($text) { echo $text . "\n"; } };
call_user_func(function() { $myScopeVariable = "嘿,这不是 JavaScript!"; console::log($myScopeVariable); });
例如 JavaScript:
/* javascript requires brackets because semicolons are not mandatory */
var almost_echo = (console.log.bind(console));
结论
您可以在 PHP 和 JavaScript 之间进行转换,但将 PHP 转换为 JavaScript 比将 JavaScript 转换为 PHP 容易得多,因为 JavaScript 本身更具表现力,而 PHP 必须创建类来表示许多 JavaScript 结构(有趣的是,php 可以预处理 php 以修复所有这些问题)。
幸运的是,PHP 现在可以原生理解 JSON,因此在 javascript 评估自身之后,javascript 可以读取结果结构(JavaScript 中的大多数内容是对象或函数),包括源代码,并将这些对象放入 JSON 编码形式。之后,您可以让 PHP 解析 JSON 以通过中性形式恢复代码)。
例如
php: jsEval('function(a){return a;}');
js: [{"type":"function", "name": "foo", "args":["a"], body: "return a"}]
php: oh, i get it, you mean
function foo($a) { return $a; }
本质上,可以说是通过“通用 LISP”进行通信。当然,这将是非常昂贵的并且不是原生的,但是演示一个示例很好。理想情况下,我们将拥有一个封装各种脚本的本机module,它可以轻松地将 ruby 转换为 php,将 perl 转换为 python 到 javascript,然后将结果编译为 c 以实现它)。javascript 通过能够评估自己以及打印自己的代码来帮助接近这一点。如果所有语言都可以做这两件事,那么实现起来会容易得多,但遗憾的是 javascript 只是“几乎在那里”(没有 un-eval 函数,您可以轻松发明它,但还没有)
至于更新DOM。PHP 可以像 JavaScript 一样轻松地做到这一点。问题是 javascript 和 php 都不知道 DOM 是什么,只是在浏览器中,dom 很方便地被挂钩为“窗口”对象。你只是表现得好像窗口在那里一样,当 php 被评估为 javascript 时,它将再次获得对 DOM 的访问权限。然而,要使用 dom,代码必须是“面向回调的”,因为它在被评估之前不会得到 dom,但这还不错,你只是在评估完成之前什么都不做,然后执行dom 可用后立即执行整个操作。
代码如下所示:
(() => {
var php_code = `
function ($window) {
$window::document::getElementById('myDIV')->innerHTML = "Hello, World!";
};
`;
window.addEventListener('load', () => {
(eval(php_code(window)))();
});
})();
虽然正确的做法是让函数评估为一个Promise(Promise是通用的......只要你在所有语言中实现它们......)。之后,它就变成了处理本质上独立于语言的Promise/意图的问题(具体来说,意图是语言独立的,一旦意图被翻译,意图将需要依赖关系,这些依赖关系可能会或可能不会被提供来实际执行从头到尾的顺序)。
希望有一天我们会看到 JavaScript 可以评估 PHP 和 PHP 可以无缝评估 JavaScript 的未来,至少可以完成混淆圈,允许我们编写客户端 php 和服务器端 javascript(我们已经完成了一半!)
一些结束的想法
php、perl、lisp 和其他 lambda 演算同义词需要它们自己的内置 JSON 变体。它基本上是 eval 和 uneval,但更简单,因为它没有处理更令人兴奋的数据结构,如函数(JavaScript 可以使用 toString 对它进行 uneval,Perl 可以使用 Data::Dumper 并将 Data::Dumper::Deparse 设置为1)。
每个 lambda 演算同义词语言(php,perl,lisp,...,其中语句(function(a){return function(b){return a + b;}})(2)(3)
是有意义的(天真地甚至汇编可以通过堆栈挖掘来做到这一点,所以它有点像 lambda 演算同义词语言,并且也可以有自己的变体JSON) 应该能够将一串有效代码编码为一个通用的抽象表示,该表示可以编码为任何其他 lambda 演算同义词语言,也可以从其中解码。
- 函数式编程原则规定,每个动作都可以分解为执行动作的请求,一个“提交列表”的转换,它堆叠提交而不执行它们,然后将提交映射到全局环境的实际转换(无论是纯的,通过创建一个新环境并进行尾递归/将其放在队列中并使未来的操作与新环境一起工作;或者不纯,通过改变全局状态并继续前进;两者与适当的抽象机制等效)。这意味着您可以在 ajax 请求中发送一个 php 脚本,让服务器在虚拟提交对象上象征性地执行它,然后将它需要执行的操作列表返回给客户端,以使其看起来像是执行了 php)。