PHP 在服务器上运行:它生成页面,发送生成好的 HTML,然后结束。JavaScript 在访问者的浏览器中运行,它响应点击,并在页面加载后修改页面;借助 Node.js,它也能在服务器上运行。所以两者与其说是对手,不如说是搭档:典型的网站在服务器上用 PHP(或 Node.js),在浏览器中用 JavaScript。
下面这段 PHP 代码在服务器上运行。浏览器只会收到它输出的内容,“页面”标签页显示的就是这个结果:
看看“输出”标签页:里面已经没有任何 PHP,只有 HTML。同样的列表如果在浏览器中用 JavaScript 构建,是这样的:
const products = [
{ name: "Keyboard", price: 49 },
{ name: "Mouse", price: 19 },
{ name: "Monitor", price: 189 },
];
const ul = document.querySelector("#cart"); // an empty <ul id="cart"> in the HTML
for (const p of products) {
const li = document.createElement("li");
li.textContent = `${p.name}: $${p.price}`;
ul.append(li);
}
PHP 版本发送的是完整的页面,搜索引擎和速度慢的手机都能立刻读取。JavaScript 版本则可以稍后更新列表而无需刷新页面,比如访问者删除某一项时。
两种语言分别在哪里运行
| PHP | JavaScript | |
|---|---|---|
| 运行环境 | Web 服务器(或终端) | 浏览器,以及借助 Node.js、Deno 或 Bun 的服务器 |
| 能访问 | 文件、数据库、环境变量、密钥 | 页面(DOM)、点击、浏览器的存储 |
| 生命周期 | 每个请求运行一次 | 页面打开期间一直存在(浏览器),或一个长期运行的进程(Node.js) |
| 典型工作 | 生成页面、处理表单、API、访问数据库 | 交互、实时更新、单页应用、Node.js 服务器 |
| 访问者能看到代码吗 | 不能 | 能,在浏览器中 |
最后一行关系到安全:浏览器 JavaScript 中的任何内容访问者都看得到,所以密码、API 密钥和价格校验都应该放在服务器上。
语法对照
两种语言看起来很像,因为它们都借鉴了 C:花括号、if、for、while、function、return。区别在细节上:
| 任务 | PHP | JavaScript |
|---|---|---|
| 变量 | $name = "Ada"; | let name = "Ada"; |
| 常量 | const MAX = 10; | const MAX = 10; |
| 连接字符串 | "Hi " . $name | "Hi " + name |
| 模板字符串 | "Hi $name" | `Hi ${name}` |
| 列表 | ["a", "b"] | ["a", "b"] |
| 键值对 | ["id" => 1] | { id: 1 } |
| 长度 | count($list)、strlen($s) | list.length、s.length |
| 循环 | foreach ($list as $item) | for (const item of list) |
| 箭头函数 | fn($x) => $x * 2 | (x) => x * 2 |
| 输出 | echo "Hi"; | console.log("Hi"); |
下面是 PHP 中一个带回调的函数:
在 JavaScript 中,map 和 filter 是数组的方法:
const prices = [12.5, 8, 30, 4.25];
const withTax = prices.map((p) => Math.round(p * 1.2 * 100) / 100);
const cheap = withTax.filter((p) => p < 15);
console.log(withTax.join(", "));
console.log("Under 15: " + cheap.join(", "));
+ 运算符:经典陷阱
在 JavaScript 中,+ 既做数字加法又连接字符串,所以只要有一个字符串,加法就会变成拼接。PHP 把两者分开:+ 永远做加法,. 永远做连接。
console.log("10" + 5); // "105"
console.log("10" - 5); // 5
console.log("3" * "4"); // 12
console.log(0.1 + 0.2 === 0.3); // false
两种语言都有松散的 == 和严格的 ===。建议也一样:除非你确实要跨类型比较,否则使用 ===。
把数据从 PHP 传给 JavaScript
PHP 先运行,所以它可以把数据直接写进页面,供浏览器中的 JavaScript 使用。json_encode 能把 PHP 数组转换成合法的 JavaScript:
“输出”标签页显示生成的脚本,数据已经填好了。JSON_HEX_TAG 标志会转义 < 和 >,所以包含 </script> 的值无法提前结束脚本。更多选项见 json_encode。
反方向则通过 HTTP 实现:浏览器中的 JavaScript 调用 fetch("/api/cart.php"),PHP 脚本运行,并用 JSON 作答:
<?php
// api/cart.php
header('Content-Type: application/json');
echo json_encode(['items' => 3, 'total' => 257]);
const res = await fetch("/api/cart.php");
const cart = await res.json();
console.log(cart.total); // 257
服务器端的 PHP 与 Node.js
当 JavaScript 通过 Node.js 在服务器上运行时,两者的比较就成了真正的选择题。
| PHP | Node.js | |
|---|---|---|
| 模型 | 每个请求重新运行一次,互不共享 | 一个带事件循环的长期运行进程 |
| 等待 I/O | 阻塞当前请求(其他请求在其他 worker 中运行) | 非阻塞,async/await |
| 擅长 | 服务端渲染的网站、CMS、经典的增删改查应用 | 实时应用、WebSocket、大量空闲连接 |
| 托管 | 任何共享主机、PHP-FPM | Node 进程管理器或 Vercel 这样的平台 |
| 主流框架 | Laravel、Symfony、WordPress | Express、NestJS、Next.js |
| 前后端同一种语言 | 否 | 是 |
PHP 的模型容错性强:bug 或内存泄漏只会影响一个请求,而每个请求都从干净的状态开始。Node 的模型可以保持状态和连接,适合聊天和实时仪表盘,但一次崩溃或一个阻塞的循环会影响这个进程的所有用户。
该学哪个
任何可交互的网页都需要 JavaScript,因为它是浏览器唯一运行的语言。真正的问题是服务器上用什么:
- 接下来学 PHP:如果你想做 WordPress、Laravel 或大量现有 PHP 网站的开发,或者想用最简单的方式把动态网站放到便宜的主机上。从 PHP 是什么开始。
- 继续学 JavaScript(Node.js):如果你想整个技术栈只用一种语言,或者要开发实时功能。
常见的学习路径是先学 HTML 和 CSS,然后是浏览器中的 JavaScript,再学一门服务器语言。无论选择哪门服务器语言,表单、会话、数据库和 JSON API 都建立在同样的 HTTP 概念上,所以学到的知识可以通用。
常见问题
JavaScript 能取代 PHP 吗?
在服务器上可以:Node.js(配合 Express、Next.js 等)能完成和 PHP 一样的工作。但在浏览器中,PHP 完全无法取代 JavaScript,因为浏览器只运行 JavaScript。所以很多网站在服务器上用 PHP 或 Node,在浏览器中用 JavaScript。
怎么把 PHP 变量传给 JavaScript?
把它以 JSON 的形式输出到页面中:<script>const user = <?= json_encode($user, JSON_HEX_TAG) ?>;</script>。json_encode 能为字符串、数字、数组和对象生成合法的 JavaScript,而 JSON_HEX_TAG 可以防止数据中的 </script> 提前结束标签。
JavaScript 能调用 PHP 函数吗?
不能直接调用,因为 PHP 在服务器上运行,而 JavaScript 在浏览器中运行。JavaScript 用 fetch('/api.php?id=3') 发送一个 HTTP 请求,PHP 脚本运行并输出响应(通常是 JSON),然后 JavaScript 读取它。
PHP 比 Node.js 快吗?
取决于具体的工作负载。Node.js 靠事件循环,擅长同时处理大量慢速连接(聊天、WebSocket)。启用 OPcache 的 PHP 8 处理普通的请求和响应页面也很快。对大多数网站来说,瓶颈在数据库,而不在语言。