Originally published on php-to-js.learnio.dev — part of the PHP to JavaScript course. View this lesson on the original site.
Closures let inner functions remember outer variables
A closure is a function that still sees variables from the scope where it was created. PHP needs use ($x); JavaScript captures automatically — essential for callbacks and factories.
PHP habit
<?php
function makeMultiplier(float $factor): Closure {
return function (float $x) use ($factor): float {
return $x * $factor;
};
}
$double = makeMultiplier(2);
echo $double(5); // 10
JavaScript equivalent
function makeMultiplier(factor) {
return function (x) {
return x * factor;
};
}
const double = makeMultiplier(2);
console.log(double(5)); // 10
| PHP | JavaScript |
|---|---|
use ($factor) |
Automatic capture |
use (&$count) for reference |
Reassign outer let in closure |
| Returning anonymous function | Returning function expression |
Real callback: run later
function later(fn) {
setTimeout(fn, 0);
}
let count = 0;
later(() => {
count += 1;
console.log('count inside callback', count);
});
console.log('scheduled, count now', count);
The callback closes over count. PHP does not schedule like this in the request cycle — the browser or Node event loop does.
Factory with private state
function makeCounter() {
let value = 0;
return {
inc() { value += 1; return value; },
read() { return value; },
};
}
const a = makeCounter();
const b = makeCounter();
console.log(a.inc(), a.inc(), b.inc()); // 1, 2, 1
Each call to makeCounter gets its own value cell — like separate closure instances in PHP.
Try it
Use the amber Try it panel below. Click Run.
const mult = makeMultiplier(3);
const prices = [10, 20, 30];
const scaled = prices.map((p) => mult(p));
console.log(scaled);
const counter = makeCounter();
console.log(counter.inc(), counter.inc());
You should see [30, 60, 90] and 1 then 2. That is closure + callback shape in everyday code.
From PHP to JavaScript — Control Flow, Functions, and Scope