PHP runs on the server: it builds the page, sends the finished HTML, and stops. JavaScript runs in the visitor's browser, where it reacts to clicks and changes the page after it has loaded; with Node.js it can also run on the server. So the two are less rivals than partners: a typical site uses PHP (or Node.js) on the server and JavaScript in the browser.
This PHP code runs on the server. The browser only receives what it prints, and the Page tab shows that result:
Look at the Output tab: there is no PHP left in it, only HTML. The same list built by JavaScript in the browser looks like this:
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);
}
The PHP version sends a complete page, which search engines and slow phones read immediately. The JavaScript version can update the list later without reloading, for example when the visitor removes an item.
Where each language runs
| PHP | JavaScript | |
|---|---|---|
| Runs in | the web server (or a terminal) | the browser, and the server with Node.js, Deno or Bun |
| Sees | files, databases, environment, secrets | the page (DOM), clicks, the browser's storage |
| Lifetime | one run per request | as long as the page is open (browser), or one long process (Node.js) |
| Typical job | build pages, handle forms, APIs, talk to the database | interactivity, live updates, single-page apps, Node.js servers |
| Visitor can read the code | no | yes, in the browser |
The last row matters for security: anything in browser JavaScript is visible to the visitor, so passwords, API keys and price checks belong on the server.
Syntax side by side
The two languages look alike because both borrow from C: braces, if, for, while, function, return. The differences are in the details:
| Task | PHP | JavaScript |
|---|---|---|
| Variable | $name = "Ada"; | let name = "Ada"; |
| Constant | const MAX = 10; | const MAX = 10; |
| Join strings | "Hi " . $name | "Hi " + name |
| Template string | "Hi $name" | `Hi ${name}` |
| List | ["a", "b"] | ["a", "b"] |
| Key/value | ["id" => 1] | { id: 1 } |
| Length | count($list), strlen($s) | list.length, s.length |
| Loop | foreach ($list as $item) | for (const item of list) |
| Arrow function | fn($x) => $x * 2 | (x) => x * 2 |
echo "Hi"; | console.log("Hi"); |
Here is a function with a callback in PHP:
And in JavaScript, where map and filter are methods on the array:
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(", "));
The + operator: the classic trap
In JavaScript + both adds numbers and joins strings, so a string anywhere turns addition into concatenation. PHP keeps the two apart: + always adds and . always joins.
console.log("10" + 5); // "105"
console.log("10" - 5); // 5
console.log("3" * "4"); // 12
console.log(0.1 + 0.2 === 0.3); // false
Both languages also have loose == and strict ===. The advice is the same in both: use === unless you mean to compare across types.
Pass data from PHP to JavaScript
PHP runs first, so it can write data straight into the page for the browser's JavaScript to use. json_encode turns a PHP array into valid JavaScript:
The Output tab shows the generated script with the data already filled in. The JSON_HEX_TAG flag escapes < and >, so a value containing </script> cannot end the script early. More on the options in json_encode.
The other direction works through HTTP: browser JavaScript calls fetch("/api/cart.php"), the PHP script runs, and it answers with 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 vs Node.js on the server
When JavaScript runs on the server through Node.js, the comparison becomes a real choice.
| PHP | Node.js | |
|---|---|---|
| Model | a fresh run per request, shared nothing | one long-running process with an event loop |
| Waiting for I/O | blocks that request (other requests run in other workers) | non-blocking, async/await |
| Good at | server-rendered sites, CMSs, classic CRUD apps | real-time apps, websockets, many idle connections |
| Hosting | any shared host, PHP-FPM | a Node process manager or a platform such as Vercel |
| Big frameworks | Laravel, Symfony, WordPress | Express, NestJS, Next.js |
| One language front and back | no | yes |
PHP's model is forgiving: a bug or memory leak only affects one request, and each request starts clean. Node's model can keep state and connections open, which suits chat and live dashboards, but a crash or a blocking loop affects every user of that process.
Which to learn
You will need JavaScript for any interactive web page, because it is the only language browsers run. The question is what runs on the server:
- Learn PHP next if you want to work with WordPress, Laravel or the many existing PHP sites, or if you want the simplest way to put a dynamic site on cheap hosting. Start with what PHP is.
- Stay with JavaScript (Node.js) if you want one language for the whole stack or are building real-time features.
A common path is HTML and CSS, then JavaScript in the browser, then one server language. Whichever server language you choose, forms, sessions, databases and JSON APIs work on the same HTTP ideas, so the knowledge transfers.
Frequently Asked Questions
Can JavaScript replace PHP?
On the server, yes: Node.js (with Express, Next.js or similar) does the same jobs as PHP. In the browser, PHP cannot replace JavaScript at all, because browsers only run JavaScript. That is why many sites use PHP or Node on the server and JavaScript in the browser.
How do I pass a PHP variable to JavaScript?
Print it into the page as JSON: <script>const user = <?= json_encode($user, JSON_HEX_TAG) ?>;</script>. json_encode produces valid JavaScript for strings, numbers, arrays and objects, and JSON_HEX_TAG stops a </script> inside the data from closing the tag.
Can JavaScript call a PHP function?
Not directly, because PHP runs on the server and JavaScript in the browser. JavaScript sends an HTTP request with fetch('/api.php?id=3'), the PHP script runs and prints a response (usually JSON), and JavaScript reads it.
Is PHP faster than Node.js?
It depends on the workload. Node.js handles many simultaneous slow connections (chat, websockets) well thanks to its event loop. PHP 8 with OPcache is fast for ordinary request and response pages. For most sites the database is the bottleneck, not the language.